github 저장소 taeung515/team-click-war
동시성 문제와 캐싱 전략을 주제로 간단한 팀 프로젝트를 진행했습니다. 저는 인기 검색어를 캐싱하여 성능을 극대화하는 것을 목표로 삼았고, 캐시 방식 선택 과정에서 데이터 동기화 문제를 깊이 고민했습니다. 로컬 캐시 대신 Redis를 도입하게 된 배경과 그 이유까지 포함해, 프로젝트를 통해 얻은 인사이트들을 기록했습니다.

인기 검색어 조회를 이해하기 전에, 먼저 캐시 전략에 대해 설명드릴 필요가 있습니다. 저희는 강의 조건 검색 시 keyword를 바로 DB에 저장하는 Write-Around 방식을 선택했습니다.
그리고 인기 검색어를 조회할 때는 Look-Aside 전략을 적용했습니다. 이로써 매 요청마다 DB에 접근하지 않고 캐시에서 먼저 데이터를 조회함으로써, 가장 큰 비용이 드는 Disk IO를 효과적으로 줄였습니다.결과적으로 대량의 요청이 들어와도 DB 디스크 IO를 최소화하여, 서비스의 처리 속도를 크게 높일 수 있었습니다.


왜 Redis를 사용했을까요? Redis는 Remote Dictionary Server의 약자로 말 그대로 원격에서 데이터를 관리하는 캐시 서버입니다. 인메모리 캐시만 사용할 경우, 서버를 여러 대로 확장(Scale-Out)했을 때 각 WAS 서버는 자신의 메모리에만 캐시를 저장하기 때문에 서로의 캐시 정보를 공유할 수 없습니다. 이로 인해 데이터 일관성 문제가 발생할 수 있습니다.
반면 Redis와 같은 공유 캐시를 도입하면 모든 서버가 동일한 캐시 데이터를 바라보기 때문에 데이터 일관성과 신뢰성을 확보할 수 있습니다.
물론, 인기 검색어와 같이 데이터의 완벽한 정합성이 크게 중요하지 않은 경우 단순 인메모리 캐시만으로도 충분합니다. 하지만 저희는 학습 차원에서 실제로 Redis를 적용해 보면서 분산 캐시의 장점과 구조를 경험해 보고자 했습니다.

동기화 되지 않은 cache의 값을 주기적으로 읽는다면??????????????????
캐시 무효화 전략
@CacheEvict 어노테이션 활용
@CacheEvict 어노테이션을 활용하면 효과적으로 캐시를 관리할 수 있습니다.
원본 데이터에 변경이 발생할 때마다 관련 캐시 데이터를 즉시 삭제하여 실시간으로 동기화합니다. 다음 요청 시에는 다시 최신 데이터를 읽어와 캐시에 저장하도록 합니다.
TTL (Time To Live) 설정
TTL 설정을 통해 캐시 데이터의 생존 시간을 제한할 수 있습니다.
일정 시간이 지나면 자동으로 캐시가 만료되어 최신 데이터를 보장합니다. 캐시와 DB 데이터 간 동기화 문제를 근본적으로 해결할 수 있습니다.
🚨Cache Stampede 문제🚨
TTL 만료나 @CacheEvict로 캐시가 무효화된 직후, 동시에 대량의 요청이 몰린다면????????????
해결방안
1. Lock 기반 접근법 (Single Flight Pattern)
- 첫 번째 요청만 DB에서 데이터를 조회하도록 락을 설정
- 나머지 요청들은 첫 번째 요청의 결과를 기다림
- Redis의 SET NX EX 명령어나 분산 락 활용
2. Stale-While-Revalidate 패턴
- 캐시 만료 시 즉시 삭제하지 않고 백그라운드에서 갱신
- 만료된 캐시를 임시로 제공하면서 동시에 새 데이터 로드
- 사용자 경험과 DB 안정성을 동시에 확보
3. 계층적 캐시 무효화
- 모든 캐시를 한번에 무효화하지 않고 단계적으로 처리
- 핵심 데이터 우선 갱신, 부차적 데이터는 지연 갱신
- 트래픽 분산 효과로 DB 부하 완화
4. Pre-warming 전략
- 캐시 무효화 예정 시점에 미리 새로운 캐시 준비
- 무효화와 동시에 새 캐시로 즉시 교체
- Blue-Green 배포 방식과 유사한 접근
이 방식으로 캐시와 DB 데이터 간 동기화 문제를 효과적으로 해결할 수 있습니다. 볼륨 있는 검색어나 갑작스러운 데이터의 잠복한 정합성 그리고 중복하지 않는 결우 단순 인메모리로 충분합니다. 하지만 저희는 학습 차원에서 실제로 Redis를 작용해 보완책 캐시의 정정과 구조를 경험해 보고자 했습니다.
'프로젝트 회고' 카테고리의 다른 글
| 코드 refactor 과제: 리팩토링하며 생각했던 것들과 배운 것을 기록 (0) | 2025.07.04 |
|---|---|
| 아웃소싱 팀 프로젝트 회고: Docker로 프론트 연동 (0) | 2025.06.23 |
| JWT 인증 기반 뉴스피드 프로젝트: 회고 (1) | 2025.06.05 |
| JPA Schedule 프로젝트: 구현 중 발생한 트러블슈팅 (0) | 2025.05.23 |
| JPA Schedule 프로젝트: 유지보수성과 학습을 위한 단계별 구현과정 (0) | 2025.05.23 |