Redis를 사용하여 Java Spring 애플리케이션에서 로그인 인증이 진행되는 UserDetails와 검색 결과인 Page를 캐싱.
Redis를 캐시로 채택한 이유:
- 복잡한 자료형 직렬화 지원: Redis는 리스트, 해시, 집합과 같은 복잡한 자료형을 직렬화하는 기능을 제공
- 고급 기능 제공: 대기열, 분산 락과 같은 고급 기능을 제공하여 Memcached보다 유연하고 강력한 기능을 활용가능
- 성능: 낮은 지연 시간과 높은 처리량을 제공하여 실시간 애플리케이션에 적합
의존성 추가
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
redis 캐시 설정: 각 캐시별로 다른 저장 시간을 추가
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10)) // 기본 캐시 수명 10분
RedisCacheConfiguration userDetailsCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours(1)); // userDetails 캐시 수명 1시간
RedisCacheConfiguration flightSearchCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(5)); // flightSearch 캐시 수명 5분
Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>();
cacheConfigurations.put("userDetailsCache", userDetailsCacheConfig);
cacheConfigurations.put("flightSearchCache", flightSearchCacheConfig);
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(defaultCacheConfig)
.withInitialCacheConfigurations(cacheConfigurations)
.build();
}
캐시 적용(유저 인증정보)
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Override
@Cacheable(value = "userDetailsCache", key = "#username")
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// UserDetails를 DB에서 로드하는 로직
return findUserByUsername(username);
}
page<Flight> 검색결과 캐싱을 위한 자료형
public class FlightPageWrapper implements Serializable {
private List<Flight> content;
private int pageNumber;
private int pageSize;
private long totalElements;
}
@Cacheable(value = "flightSearchCache", key = "#pageable.pageNumber + '-' + #pageable.pageSize")
public FlightPageWrapper searchFlights(Pageable pageable) {
Page<Flight> flightPage = flightRepository.findAll(pageable);
return new FlightPageWrapper(flightPage.getContent(), pageable.getPageNumber(), pageable.getPageSize(), flightPage.getTotalElements());
}
프로젝트가 완료된 후, Page<Flight>를 List<Flight>로 변환하여 저장하는 방법도 가능했을 것이라고 생각할 수 있지만, 포장된 형태가 캐싱과 역직렬화에 더 적합하다고 판단하였다.
'Diary > TIL' 카테고리의 다른 글
2024-04-19) 멀티스레드 공부 (0) | 2024.05.22 |
---|---|
2024-04-18) 로드밸런싱 공부 (0) | 2024.05.22 |
2024-04-16) 캐싱 적용 방법 탐색 (0) | 2024.05.22 |
2024-04-15) 인덱싱 적용 (0) | 2024.05.21 |
2024-04-13) 대규모 시스템 설계 기초 CH1: 규모 확장, 캐시 (0) | 2024.05.19 |