데이터베이스의 부하를 줄이고 응답 속도(Latency)를 개선하기 위해 캐시(Cache)는 선택이 아닌 필수이다.
캐시가 무엇인지, 그리고 내 서비스 상황에 딱 맞는 캐싱 전략(Caching Strategy)은 무엇인지 정리 해보자.
1. 캐시(Cache)
데이터의 원래 소스보다 더 빠르고 효율적으로 접근 할 수 있는 임시 데이터 저장소
사용되었던 데이터는 다시 사용되어질 가능성이 높다는 개념을 이용하여, 다시 사용될 확률이 높은 것은 더 빠르게 접근 가능하자는 개념
파레토의 법칙 (80:20 법칙)
"전체 요청의 80%는 상위 20%의 데이터에 집중된다."
캐시는 이 법칙에 기반합니다. 모든 데이터를 캐시에 담을 필요는 없다
자주 찾는(Hot) 20%의 데이터만 캐싱해도 전체 시스템 성능을 대폭 향상시킬 수 있다.
2. Local vs Global Cache
MSA 환경에서 캐시 저장소를 어디에 둘 것인가는 아키텍처의 성능과 정합성을 결정짓는 중요한 문제이다.
2-1. Local Cache (로컬 캐시)
각 서버(인스턴스)의 메모리(RAM) 자체를 캐시로 사용한다. (Java Ehcache, Caffeine)
장점
- 네트워크 통신이 없어 속도가 가장 빠르다.
단점
- 휘발성 메모리: 애플리케이션이 다운되면, 메모리 데이터는 사라짐
- 데이터 불일치 문제: 서버 A의 데이터가 바뀌어도 서버 B는 모른다.
- 리소스 제약: 캐시가 커지면 애플리케이션의 메모리 부족(OOM)을 유발
언제 쓰면 좋을까?
- 전역 공통 코드, 카테고리 정보, 국가 코드, 은행코드
- 변경이 거의 없는 경우
2-2. Global Cache (글로벌 캐시)
별도의 외부 캐시 서버를 두고 공유합니다. (Redis, Memcached)
장점
- 모든 서버가 동일한 최신 데이터 공유
- 확장성이 좋다.
단점
- 네트워크 트래픽 비용이 발생합
- Local Cache에 비해 상대적으로 느리다.
언제 쓰면 좋을까?
- 상품 재고, 로그인 세션, 선착순 이벤트
3. 캐싱 전략
무작정 캐시를 도입한다고 해서 성능이 좋아지는 것은 아니다.
데이터의 특성과 비즈니스 요구사항에 맞는 적절한 캐싱 전략(Caching Strategy)을 선택해야만 데이터 일관성을 유지하면서도 성능을 극대화 할 수 있다.
가장 먼저 "데이터의 읽기/쓰기 빈도에 따라 어떤 전략(Pattern)을 취할 것인가?" 고려해 보아야 한다.
3-1. 읽기 전략 (Read Strategies)
데이터를 읽어올 때 캐시를 어떻게 활용할지에 대한 전략
1) Look-aside (Lazy Loading)
"캐시를 먼저 쓱 보고(Look aside), 없으면 DB로 간다"

동작방식
1. 요청이 들어오면 애플리케이션이 캐시에 데이터가 있는지 확인한다.
2. Hit: 캐시 저장소에서 캐시에서 데이터를 읽어 반환한다.
3. Miss: 캐시에 없는 경우 DB에서 데이터를 읽어온 후, 캐시에 저장(Populate)하고 반환한다. (이때 TTL을 함께 설정하여 데이터 정합성을 보장)
장점
- 실제로 요청된 데이터만 캐시에 저장되므로 리소스 효율적이다.
- 캐시가 다운되어도 DB에서 조회 가능하므로 서비스 장애로 이어지지 않는다.
단점
- Cache Miss가 발생해야만 캐시에 저장되므로, 초기 요청(Cold Start) 시에는 지연이 발생할 수 있다. (Cache Warming으로 해결 가능)
언제 적합할까?
- 읽기가 많은 경우 적합
Cache Warming
해당 상품의 조회수가 몰릴 것을 대비해 상품 정보를 미리 DB에서 캐시로 올려주는 작업
3-2. 쓰기 전략 (Write Strategies)
데이터가 변경될 때 캐시와 DB를 어떻게 동기화할지에 대한 전략
1) Write-through (동시 쓰기)
“쓰기 요청 시 캐시 → DB 순서로 동기적 저장 후 응답”

동작방식
1. 데이터 쓰기 요청이 들어오면 먼저 캐시에 저장한다.
2. 캐시 저장이 성공하면 즉시 DB에 동기적으로 저장한다.
3. DB 저장까지 완료되어야 클라이언트에게 성공 응답을 반환한다.
장점
- 캐시는 항상 최신 데이터를 유지한다. (데이터 정합성 최상).
단점
- 매번 두 곳에 저장해야 하므로 쓰기 속도가 느립니다.
언제 적합할까?
- 금융 / 결제
- 데이터 유실이 절대 허용되지 않는 경우
2) Write-back (Write-behind)
“일단 캐시에 저장하고, DB 반영은 뒤에서 비동기로 처리”

동작방식
1. 캐시에서 쓰기 작업을 처리하고 저장한다.
2. 이후 데이터베이스에 데이터를 동기화한다.
장점
- 쓰기 속도가 극단적으로 빠르다.
- DB 부하를 획기적으로 줄일 수 있습니다.
단점
- 캐시 서버가 죽으면, DB에 반영되지 않은 데이터가 영구 유실된다.
언제 적합할까?
- 로그 수집, 조회수 카운트, 좋아요 수 등
- 오차가 허용되는 대량 쓰기 작업
4. 캐시 사용 시 반드시 알아야 할 위험 요소
캐시를 도입하는 순간, "성능"을 얻는 대신 "데이터 정합성 관리"라는 빚을 지게 된다.
DB 데이터는 1000원인데, 캐시에 900원으로 남아있다면 이는 단순한 버그가 아니라 비즈니스 사고이다.
안전한 캐시 운영을 위해 다음 3가지는 주의 하자.
① TTL (Time-To-Live) 설정
캐시는 영구 저장소가 아니다. 모든 캐시 키에 반드시 만료 시간(TTL)을 설정해야한다.
시스템 로직 상 캐시 갱신에 실패하더라도, TTL이 지나면 데이터가 자동으로 삭제되므로 DB에서 최신 데이터를 다시 불러오게 된다. 즉, TTL은 데이터 불일치를 막는 '마지막 안전장치'이다.
② 적절한 대상 선정:
"일단 다 넣고 보자"는 위험하다. 캐시 메모리는 비싸고 한정적이다.
무분별한 캐싱은 메모리를 낭비할 뿐만 아니라, 정작 중요한 데이터가 용량 부족으로 밀려나는 Eviction 현상을 초래한다.
자주 조회되지만, 잘 변하지 않는 데이터가 캐시의 주 타겟입니다. (예: 베스트셀러, 카테고리, 공통 코드)
③ Cache Stampede 주의
인기 있는 데이터의 TTL이 만료되는 찰나의 순간을 조심해야 한다. 캐시가 사라진 그 짧은 순간에 수만 개의 요청이 동시에 들어오면, 모든 요청이 DB를 직접 때리게 되어 DB가 순간적으로 다운될 수 있다.
- 해결책: 만료 시간을 랜덤하게 분산시키는 Jitter를 적용하거나, Mutex Lock을 사용하여 한 번에 하나의 요청만 DB에 접근하도록 제어해야 한다.
5. 결론
MSA에서 캐시는 선택이 아닌 생존을 위한 필수 무기이다.
하지만 무턱대고 도입하기보다, 내 서비스의 읽기/쓰기 패턴을 파악하여 적절한 전략(Look-aside vs Write-back)을 선택하는 것이 중요하다.
처음에는 Global Cache(Redis)로 정합성을 챙기고, 극한의 성능이 필요한 정적 데이터에 한해 Local Cache를 혼용하는 전략도 고려야 해보아야한다
[요약] 상황별 추천 전략
| 시나리오 | 추천 전략 | 이유 |
| 일반적인 읽기 위주 서비스 | Look-Aside + TTL | 장애 격리가 쉽고 효율적임 (표준) |
| 데이터 일관성 필수 (금융) | Write-Through | 캐시와 DB 간의 데이터 불일치 원천 차단 |
| 쓰기 빈도 폭주 (로그, 좋아요) | Write-Back | DB 쓰기 부하를 최소화하여 성능 확보 |