-
Spring Boot 시리즈 16편 – 고급 캐시 전략: 멀티 레벨 캐시(L1+L2)와 데이터 일관성 관리개발/Spring Boot 2025. 4. 27. 15:30
Spring Boot에서 멀티 레벨 캐시(L1+L2) 전략을 구현하고, 데이터 일관성 문제를 해결하는 방법을 설명합니다. 실전 아키텍처와 보완 설계까지 포함했습니다.
Spring Boot 시리즈 16편 – 고급 캐시 전략: 멀티 레벨 캐시(L1+L2)와 데이터 일관성 관리
API 응답 속도를 높이고, 서버 부하를 줄이는 데에 **캐시(Cache)**는 필수적인 존재입니다.
하지만 단순한 캐시 적용만으로는 변경된 데이터가 반영되지 않거나,
동시성 문제로 인해 잘못된 정보가 노출되는 문제를 막을 수 없습니다.
이번 글에서는 Spring Boot 환경에서 멀티 레벨 캐시를 구축하고,
속도 + 일관성 + 복원력을 동시에 확보하는 방법을 실무 사례 기반으로 설명합니다.
📌 1. 기본 캐시 구조와 한계
항목설명
1단계(L1) 로컬 메모리(Heap) 캐시 (예: Caffeine) 2단계(L2) 분산 캐시(예: Redis) 한계점 변경/갱신 시점 문제, 캐시-DB 간 불일치 발생 가능
✅ 2. 멀티 레벨 캐시(Multi-Level Cache) 개념
✅ 기본 구성
[요청] ↓ [L1 캐시] (Heap 메모리) → MISS → [L2 캐시] (Redis) → MISS → [DB 조회] ↓ ↓ 응답 저장 (L1 + L2 업데이트)
- 1차 캐시(L1): 초고속 응답 (Heap 메모리, 단일 서버 범위)
- 2차 캐시(L2): 분산 시스템에서 데이터 공유 (Redis 등)
🛠️ 3. Spring Boot 환경에서 멀티 레벨 캐시 구현
1️⃣ 의존성 추가 (Gradle)
implementation 'org.springframework.boot:spring-boot-starter-cache' implementation 'com.github.ben-manes.caffeine:caffeine' implementation 'org.springframework.boot:spring-boot-starter-data-redis'
2️⃣ 캐시 설정 (application.yml)
spring: cache: type: caffeine redis: host: localhost port: 6379
- type: caffeine 설정은 기본 CacheManager를 Caffeine으로 설정
- Redis 연동은 별도로 구성 (L2 캐시 용도)
3️⃣ L1: Caffeine 캐시 설정
@Configuration public class CacheConfig { @Bean public CaffeineCacheManager caffeineCacheManager() { CaffeineCacheManager manager = new CaffeineCacheManager(); manager.setCaffeine(Caffeine.newBuilder() .expireAfterWrite(10, TimeUnit.MINUTES) .maximumSize(5000)); return manager; } }
- L1 캐시: 읽기 속도 극대화, JVM 메모리 기반
4️⃣ L2: Redis 캐시 설정
@Configuration @EnableCaching public class RedisCacheConfig { @Bean public RedisCacheManager redisCacheManager(RedisConnectionFactory connectionFactory) { RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofMinutes(30)) // L2는 더 긴 TTL 가능 .disableCachingNullValues(); return RedisCacheManager.builder(connectionFactory) .cacheDefaults(config) .build(); } }
🔁 4. 멀티 레벨 캐시 연동 전략
Spring Boot 기본 구조만으로는 L1과 L2를 자동으로 병합하지 못합니다.
Custom CacheManager를 만들어 L1(Caffeine) → L2(Redis) 순서로 조회하도록 조정해야 합니다.
1️⃣ 커스텀 MultiCacheManager 작성
public class MultiCacheManager implements CacheManager { private final CacheManager caffeineCacheManager; private final CacheManager redisCacheManager; public MultiCacheManager(CacheManager caffeine, CacheManager redis) { this.caffeineCacheManager = caffeine; this.redisCacheManager = redis; } @Override public Cache getCache(String name) { Cache caffeineCache = caffeineCacheManager.getCache(name); Cache redisCache = redisCacheManager.getCache(name); return new MultiLevelCache(caffeineCache, redisCache); } }
2️⃣ MultiLevelCache 작성
public class MultiLevelCache implements Cache { private final Cache l1; private final Cache l2; public MultiLevelCache(Cache l1, Cache l2) { this.l1 = l1; this.l2 = l2; } @Override public ValueWrapper get(Object key) { ValueWrapper value = l1.get(key); if (value == null) { value = l2.get(key); if (value != null) { l1.put(key, value.get()); } } return value; } @Override public void put(Object key, Object value) { l1.put(key, value); l2.put(key, value); } @Override public void evict(Object key) { l1.evict(key); l2.evict(key); } @Override public void clear() { l1.clear(); l2.clear(); } }
- 조회 시 → L1 → L2 순서로 조회
- 저장 시 → L1 + L2 모두 저장
- 삭제 시 → L1 + L2 모두 삭제
🧠 실무 캐시 일관성 관리 전략
항목전략
TTL 관리 L1은 짧게 (10분), L2는 길게 (30분) 설정 변경 시점 동기화 데이터 변경 API에서는 반드시 캐시 삭제/갱신 대량 갱신 대응 pub/sub or cache invalidate 기능 활용 장애 대비 L2(Redis) 장애 시에도 L1만으로 임시 대응 가능성 확보 업데이트 알림 L2 업데이트 시 L1에 invalidation push (Advanced)
✅ 마무리 요약
항목정리
기본 구조 L1(Caffeine) + L2(Redis) 멀티 레벨 구성 읽기 흐름 L1 → L2 → DB 순서 조회 쓰기 흐름 L1 + L2 모두 동시 저장 실무 주의 데이터 일관성, TTL 관리, 장애 복원력 고려 필수 고급 설계 Redis pub/sub 기반 캐시 동기화 가능
📌 다음 편 예고
Spring Boot 시리즈 17편: 트랜잭션 관리 고급 전략 – 선언적, 프로그래밍 방식, 전파/고립 수준까지 완벽 정리
'개발 > Spring Boot' 카테고리의 다른 글