Cache Aside

애플리케이션이 캐시를 직접 관리하는 가장 일반적인 캐싱 전략입니다.

동작 방식

읽기 (Read)
────────────────────────────────
1. 캐시 먼저 조회
        ↓
   캐시 Hit?
   O Yes → 캐시에서 반환 (끝)
   X No  → DB 조회 → 캐시에 저장 → 반환

쓰기 (Write)
────────────────────────────────
1. DB에 직접 저장
2. 캐시 삭제 (or 업데이트)

코드 예시

@Service
public class UserService {
    private final UserRepository userRepository;
    private final RedisTemplate<String, User> redisTemplate;

    // 읽기
    public User getUser(Long id) {
        String cacheKey = "user:" + id;

        // 1. 캐시 먼저 확인
        User cached = redisTemplate.opsForValue().get(cacheKey);
        if (cached != null) {
            return cached;  // O Cache Hit
        }

        // 2. Cache Miss → DB 조회
        User user = userRepository.findById(id).orElseThrow();

        // 3. 캐시에 저장 (TTL 10분)
        redisTemplate.opsForValue().set(cacheKey, user, 10, TimeUnit.MINUTES);

        return user;
    }

    // 쓰기
    public void updateUser(Long id, UserUpdateRequest request) {
        // 1. DB 업데이트
        userRepository.update(id, request);

        // 2. 캐시 삭제 (다음 조회 시 DB에서 최신값 로드)
        redisTemplate.delete("user:" + id);
    }
}

다른 캐싱 전략과 비교

전략캐시 관리 주체특징
Cache Aside애플리케이션직접 관리, 유연함
Read Through캐시캐시가 DB 조회 대행
Write Through캐시DB + 캐시 동시 저장
Write Behind캐시캐시 저장 후 DB는 나중에

장단점

장점
O 구조 단순, 이해하기 쉬움
O 캐시 장애 시 DB로 fallback 가능
O 필요한 데이터만 캐싱 (메모리 효율)

단점
X Cache Miss 시 DB 조회 + 캐시 저장으로 첫 응답 느림
X DB 업데이트 후 캐시 삭제 전 순간적으로 데이터 불일치 발생
X 캐시 관리 로직을 개발자가 직접 작성해야 함

캐시 불일치 문제

Thread A: DB 업데이트 완료
                        ↓
Thread B: 캐시 조회 → 아직 삭제 전 → 구버전 데이터 반환 X
                        ↓
Thread A: 캐시 삭제
// TTL로 완화 → 최대 TTL 시간 내에는 불일치 허용
redisTemplate.opsForValue().set(cacheKey, user, 10, TimeUnit.MINUTES);
// 10분 후 자동 만료 → 최신 데이터로 갱신

Cache Aside는 "캐시가 없으면 DB에서 가져와서 채운다" 는 단순한 원칙으로, 대부분의 서비스에서 Redis + RDB 조합으로 가장 많이 사용하는 전략입니다.

CSLOG에서 보기