Cahingrdb
title: 2025-11-23 author: 강병호 date: 2025-11-23 category: TIL/강병호/2025/11 (파일 경로 : TIL/{이름}/{연}/{월}) layout: post (자유) —
3. 캐싱
트래픽이 높아질 때 캐싱은 DB 부하를 줄이는 가장 효과적이고 필수적인 전략입니다. 캐싱은 자주 접근하는 데이터를 빠른 메모리 공간(캐시)에 임시 저장해 두었다가, 요청이 오면 DB를 거치지 않고 캐시에서 바로 응답하는 방식입니다.
특히 캐시의 위치, 구조, 데이터 무효화(Invalidation) 전략이 성능과 안정성을 좌우합니다.
-
캐시의 위치와 유형
유형 위치 목적 및 사용 예시 CDN 캐시 사용자에게 가장 가까운 네트워크 엣지 서버 정적 파일(이미지, CSS, JS) 배포 속도 향상. 웹 서버/리버스 프록시 캐시 웹 서버(Nginx, Apache) 앞단 또는 내부 페이지 단위의 응답 결과(HTML)를 캐시하여 WAS(Application) 부하를 줄임. 애플리케이션(WAS) 내부 캐시 WAS 메모리 (JVM Heap 등) 세션 정보, 자주 바뀌지 않는 설정 정보 등 가장 빠른 접근 속도를 제공 (예: Spring Cache, Ehcache). 분산 캐시 시스템 독립적인 서버 클러스터 별도의 서버를 구축하여 여러 WAS 인스턴스가 데이터를 공유 (예: Redis, Memcached). 매우 많이 사용됨. -
분산 캐시 시스템
대규모 서비스에서 가장 흔히 사용되며, WAS 간 데이터 공유 및 수평 확장을 가능하게 합니다.
- WAS 확장성: WAS 인스턴스가 여러 개라도 캐시 데이터는 중앙 집중식으로 관리되므로 데이터 일관성을 유지할 수 있습니다.
- 빠른 접근: 데이터를 메모리에 저장하므로 DB(디스크)보다 수백 배 빠릅니다.
- DB 보호: 대부분의 읽기 트래픽을 캐시 서버가 흡수하여 DB의 부하를 획기적으로 줄여줍니다.
패턴 설명 적합한 상황 Cache Aside (Lazy Loading) 1. 애플리케이션이 캐시에 먼저 접근. 2. 데이터가 없으면(Cache Miss) DB에서 데이터를 가져와서 캐시에 저장 후 반환. 읽기 중심 서비스. 캐시 실패 시 초기 지연이 발생해도 무방할 때. Read Through 1. 애플리케이션은 캐시 라이브러리에 요청. 2. 라이브러리가 캐시에 데이터가 없으면 DB에서 로드하여 캐시 채우기까지 대리 수행 후 반환. 라이브러리/프레임워크의 도움을 받아 코드를 단순화할 때. Write Back 쓰기 연산 시 캐시에만 먼저 기록하고, 캐시 시스템이 일정 시간 후에 비동기적으로 DB에 반영. 쓰기 성능이 매우 중요하며, 데이터 유실 위험을 감수할 수 있을 때. (높은 위험성) -
캐시 데이터 무효화 전략
캐시의 성능만큼 중요한 것은 정합성(Consistency) 유지입니다. 캐시된 데이터가 실제 DB 데이터와 다를 때 발생하는 문제를 방지하기 위해 데이터를 무효화해야 합니다.
- 3.1. 캐시 만료(Expiration) 설정
- TTL (Time-To-Live): 캐시 데이터에 만료 시간을 설정합니다. 시간이 지나면 데이터가 자동으로 삭제되어 다음 요청 시 DB에서 최신 데이터를 가져오게 합니다.
- 장점: 구현이 간단합니다.
- 단점: TTL 동안에는 데이터가 변경되어도 오래된 데이터(Stale Data)가 제공될 수 있습니다.
- 3.2. 명시적 삭제 (Explicit Deletion)
-
DB 업데이트 시 삭제: Master DB에 데이터 쓰기(Update/Delete)가 발생하면, 해당 데이터를 캐시에서 즉시 삭제하도록 애플리케이션 코드를 설계합니다. (Cache Aside 패턴의 쓰기 전략)
// 1. DB에 데이터 변경 db.update(data); // 2. 캐시에서 해당 키를 명시적으로 삭제 cache.delete(key); - 장점: 데이터 정합성을 가장 높일 수 있는 표준적 방법입니다.
- 단점: 쓰기 작업이 2단계(DB 쓰기, 캐시 삭제)로 늘어나므로, 캐시 삭제가 실패할 경우 데이터 불일치 가능성이 있습니다.
-
-
[주의] 경합 조건 문제 (Race Condition)
캐시 무효화 시 발생할 수 있는 대표적인 문제입니다.
- 사용자 A가 데이터를 읽기(Read) 위해 캐시에 접근했지만, 데이터가 없습니다 (Cache Miss).
- A는 DB에서 데이터를 가져와 캐시에 저장(Set)하려 합니다.
- 이때 사용자 B가 데이터를 변경(Write)하고, 캐시에서 삭제(Delete)합니다.
- A의 저장 작업이 완료되어, 결국 캐시에는 오래된 데이터가 다시 저장되는 문제가 발생합니다.
대응 전략: 이 경우, “먼저 DB를 업데이트하고, 이어서 캐시를 삭제”하는 순서를 엄격히 지켜야 경합 조건 발생 확률을 최소화할 수 있습니다. (Cache-Aside 패턴의 표준)