본문 바로가기
카테고리 없음

캐시의 선택적 무효화

by 차리하루일기 2024. 12. 17.

1. 배경.

현재 Redis를 활용해 특정 가게의 상세 정보, 메뉴 리스트, 리뷰 데이터를 캐싱하여 성능을 최적화하고 있습니다. 하지만 데이터 변경 시 캐시 무효화 전략이 다음과 같은 문제를 야기할 수 있다.

  • 전체 캐시 삭제의 비효율성:
  • 가게 상세 정보나 메뉴의 일부 데이터가 변경되어도 전체 캐시를 무효화하는 방식으로 인해 필요 이상의 데이터가 삭제되고 재로드 된다.
  • 데이터 일관성 문제:
  • 여러 서버에서 동시 요청 시 캐시가 즉시 갱신되지 않아, 잘못된 데이터가 반환될 가능.
  • TTL 기반 무효화 한계:
  • 리뷰 데이터는 TTL로 무효화하지만, 빈번한 데이터 갱신 시 TTL 만료 전까지 오래된 데이터가 유지될 수 있다.

2. 문제

  1. 캐시 무효화 범위의 비효율성:
  2. 데이터 변경 시 필요 이상의 캐시가 무효화되거나, 일부 데이터가 잘못 무효화될 가능성이 있음.
  3. 다중 서버 환경에서 캐시 동기화 부족:
  4. 다중 서버 간 캐시 동기화가 이루어지지 않아 데이터 일관성 문제가 발생할 가능성.
  5. 재로딩 시간의 지연:
  6. Lazy Loading 방식으로 무효화된 데이터를 다시 로드하는 과정에서 사용자가 느낄 수 있는 응답 지연.

3. 개선 목표

  • 변경된 데이터에 대한 선택적 무효화를 적용하여 필요한 범위 내에서만 캐시를 무효화.
  • 다중 서버 환경에서 Pub/Sub 기반 캐시 동기화를 통해 데이터 일관성을 유지.
  • 캐시 무효화 이후 Eager Loading을 통해 중요 데이터를 미리 로드하여 사용자 경험 개선.

4. 해결 방안

  1. 선택적 무효화
    • 변경된 데이터의 범위를 정확히 파악하여, 전체 캐시가 아닌 변경된 데이터에만 영향을 미치는 키를 무효화.
    • 예:
      • 가게 상태 변경 시 store:{storeId}:details만 무효화.
      • 메뉴 추가/수정 시 store:{storeId}:menus만 무효화.
      • 리뷰 데이터 추가/삭제 시 해당 리뷰 페이지만 무효화: store:{storeId}:reviews:page:{pageNumber}.
  2. Pub/Sub 기반 캐시 동기화
    • Redis Pub/Sub를 활용해 서버 간 캐시 무효화 메시지를 전파:
      • 예: 메뉴 변경 시 invalidate store:{storeId}:menus 메시지를 다른 서버로 전송.
    • Spring Data Redis의 RedisMessageListener를 활용:
@Component
public class CacheInvalidationSubscriber {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @PostConstruct
    public void subscribe() {
        redisTemplate.convertAndSend("cache-invalidation", "store:{storeId}:menus");
    }
}

 

   3. 캐시 재로딩(Eager Loading)

  • 캐시가 무효화된 후 Lazy Loading 대신 중요한 데이터를 미리 채우기.
  • 예: @CacheEvict 이후 데이터를 즉시 갱신:
@CacheEvict(value = "storeDetails", key = "'store:' + #storeId + ':details'")
public void updateStore(Long storeId, UpdateStoreRequest req) {
    // DB 업데이트 후 캐시 재로드
    StoreDetailsResponse updatedDetails = getStoreDetails(storeId);
    redisTemplate.opsForValue().set("store:" + storeId + ":details", updatedDetails);
}

 

   4. TTL 동적 설정

  • 변경 빈도가 높은 데이터(예: 리뷰)는 짧은 TTL을 설정하여 데이터 변경 후 캐시 자동 갱신을 유도:
  • yaml 코드 복사 spring: cache: redis: time-to-live: storeDetails: 600s # 10분 reviews: 300s # 5분
yaml

spring:
  cache:
    redis:
      time-to-live:
        storeDetails: 600s  # 10분
        reviews: 300s       # 5분

5. 기대 효과

  • 캐시 무효화 범위 축소: 변경된 데이터에만 영향을 미쳐 재로드 성능 최적화.
  • 데이터 일관성 개선: Pub/Sub로 다중 서버 환경에서 캐시 동기화 문제 해결.
  • 응답 속도 향상: Eager Loading을 통해 사용자 요청 시 데이터가 이미 준비된 상태로 제공.
  • 유지보수성 향상: 캐시 키와 데이터의 매핑 관계를 명확히 정의하여 오류 가능성 감소.