Spring boot - Cache (2) 페이지 조회 캐싱

2025. 1. 8. 11:00·Spring/SpringBoot

이전 포스팅에서 스프링부트의 캐싱을 사용방법을 알아봤다.

이번 포스팅에서는 페이징 처리에 캐시를 도입하기 위한 방법을 살펴본다.

어느 부분을 캐싱할래?

캐시는 key-value로 캐시 메모리에 저장된다.
페이징 조회에서 사용되는 key는 Pageable에서 사용되는 sort,size, offset임으로, 특정 레코드의 데이터가 변경됐을 때, 이 데이터가 포함된 캐시를 갱신할 수 없다.

예시를 들어보자.

    // 1. id 를 이용해 특정 사용자의 이름을 수정하는 메소드
    @Caching(
            put = @CachePut(key = "#id"),
            evict = @CacheEvict("'all'")
    )
    @Transactional(readOnly = false)
    public Member changeName(final Long id, final String name) {
        final Member member = memberRepository.findById(id).orElseThrow();
        member.setName(name);
        return member;
    }
}

위와 같이 특정 사용자의 이름을 수정하는 로직이 존재한다.

    // 2. 페이지 기반으로 모든 Member 조회
    @Cacheable(key = "#pageable.offset + '-' + #pageable.pageSize + '-' + #pageable.sort")
    public Page<Member> queryByPage(final Pageable pageable) {
        return memberRepository.findAll(pageable);
    }

이 경우, (1)에서 수정되는 사용자의 id로는 캐싱된 페이지의 key를 알 수 없음으로, 해당 캐시를 갱신할 수 없다.

따라서, 다음과 같은 방법으로 대안한다.

1. 모든 페이징 요청 캐싱 + 갱신(수정, 삭제, 추가) 시 초기화

사용자에게 항상 최신정보를 전달할 수 있다.
다만, 수정과 삭제가 빈번한 도메인의 경우 전체 캐시 메모리가 빈번히 Evict됨에 따라, 쿼리가 자주 발생하게 됨으로, 캐시메모리를 도입한 의의가 없어진다 볼 수 있다.

2. 모든 페이지 요청 캐싱 + TTL 최소화

쿼리를 획기적으로 줄일 수 있다.
다만, 사용할 수 없는 데이터가 쿼리 결과에 일정시간 존재함에 따라, 사용자 경험을 떨어뜨릴 수 있다. (최신 정보 전달 불가)

@Configuration
@EnableCaching
public class CacheConfig {
    @Autowired
    RedisProperties redisProperties;

    @Bean
    RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory(
               redisProperties.getHost(),
               redisProperties.getPort()
        );
    }

    RedisCacheConfiguration redisCacheConfiguration() {
        return RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(60))
                .serializeKeysWith(SerializationPair.fromSerializer(RedisSerializer.string()))
                .serializeValuesWith(SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
                .disableCachingNullValues();
    }

    @Bean
    CacheManager cacheManager() {
        return RedisCacheManagerBuilder
                .fromConnectionFactory(redisConnectionFactory())
                .cacheDefaults(redisCacheConfiguration())

                // Page Cache를 위한 로직 설정 TTL 10초 설정
                .withCacheConfiguration("pageCache", redisCacheConfiguration().entryTtl(Duration.ofSeconds(10L)))
                .build();
    }
}

위와 같이 pageCache를 설정한다.

@Transactional(readOnly = true)
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "pageCache")
public class MemberQueryService {
    private final MemberRepository memberRepository;

    @Cacheable(key = "#pageable.offset + '-' + #pageable.pageSize + '-' + #pageable.sort")
    public PageResponse<Member> queryByPage(final Pageable pageable) {
        return mapToPage(memberRepository.findAll(pageable));
    }

    private PageResponse<Member> mapToPage(final Page<Member> members) {
        return new PageResponse<Member>(members.getContent(), members.getSize(), members.getTotalPages());
    }
}

pageCache를 사용하여 페이징 처리하며, 10초마다 이를 파기한다.

특정 데이터가 수정될 떄, 해당 데이터가 포함된 페이징 캐시만 수정할 수 있다면 좋겠지만, 페이징 쿼리의 특성 상, 조회 조건이 여럿으로 걸릴 수 있음으로이에 대한 모든 캐시를 업데이트하는 것은 추가적인 오버헤드가 발생한다.

 

사용자가 많고, 수정 및 추가 이벤트가 빈번한 도메인의 경우 TTL을 적절히 조정하며 가장 적절한 상수를 찾는것이 좋아보인다.

'Spring > SpringBoot' 카테고리의 다른 글

[Spring boot] Repository의 메소드 노출  (0) 2025.04.04
Spring boot - @Transactional 전파 주의 사항  (0) 2025.01.13
Spring boot - Cache  (0) 2025.01.07
[SpringBoot] 스프링의 에러처리 탐구  (0) 2024.01.17
[Spring] Spring Security 인증 구성  (0) 2024.01.02
'Spring/SpringBoot' 카테고리의 다른 글
  • [Spring boot] Repository의 메소드 노출
  • Spring boot - @Transactional 전파 주의 사항
  • Spring boot - Cache
  • [SpringBoot] 스프링의 에러처리 탐구
윤희종
윤희종
호기심을 잃지 말자 지적, 질문은 언제나 환영합니다 ;)
  • 윤희종
    서버견문록
    윤희종
  • 전체
    오늘
    어제
    • 분류 전체보기 (36)
      • 데일리 플랜 (1)
      • 이것저것 (4)
      • Java (6)
      • Spring (12)
        • SpringBoot (10)
        • Spring MVC (0)
      • Computer Science (4)
        • Network (1)
        • Operating System (0)
        • Data Structure (0)
        • Algorithm (2)
        • Database (0)
      • IOS (0)
      • 프로그래머스 문제풀이 (2)
      • 프로젝트 일기 (7)
        • 한편의 수학 학원 (7)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    스프링 시큐리티 사용법
    SecurityFilterChain
    SecurityFilterChain 구성
    인증 우회 테스트
    인증 테스트
    스프링 부트
    springboot
    servlet
    제네릭
    캐시
    스프링
    알고리즘
    Spring
    read through
    mysql 쿼리 최적화
    cache write back
    스프링 시큐리티 구성
    성능 개선
    스프링 부트 인증 우회
    비동기 처리 유의점
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
윤희종
Spring boot - Cache (2) 페이지 조회 캐싱
상단으로

티스토리툴바