카카오테크 부트캠프

동적인 데이터 캐시 동시성 제어 전략 비교 및 분산 락 선택

kanado 2025. 7. 15. 15:09

요약

이 글은 튜닝 레포트 시스템에서 사용자의 동시 리액션 요청이 발생할 때 Redis 캐시의 JSON 객체가 충돌하며 생기는 Race Condition 문제를 어떻게 해결했는지, 실전 적용 경험을 바탕으로 정리한 기술 포스트다.

다음과 같은 내용을 다룬다.

문제 정의: Redis에 저장된 JSON을 동시에 수정할 때 발생하는 동시성 충돌

  • 5가지 대안 기술 비교: HINCRBY, Lua Script, Redis WATCH, SessionCallback, Redisson 분산 락
  • 선택 기준과 검토 포인트: 구조 호환성, 유지보수 난이도, 멀티 인스턴스 적합성 등
  • 최종 선택 – Redisson RLock: 기존 JSON 구조를 유지하며, Spring Boot 환경에서 안전하고 직관적으로 구현 가능

 

문제 정의

멀티 인스턴스(WAS) 환경에서 사용자가 동시에 게시글에 리액션을 보낼 경우,

Redis에 캐싱된 ReportItem JSON 객체를 "읽기 → 수정 → 다시 쓰기"하는 과정에서
Race Condition(동시성 충돌)이 발생할 수 있음.

예시 문제

  • 두 사용자가 동시에 HEART(반응)를 누르면,
  • 동일한 JSON을 읽고 각각 +1 후 저장 → 최종 반영은 한 번뿐 → 리액션 수가 실제보다 적게 저장됨

 

고려한 대안들

1. Redis Hash + HINCRBY

  • 구조: 리액션 수치를 Redis Hash에 따로 저장 → HINCRBY reactions:{reportId} HEART 1
  • 장점: Redis 원자 연산 → 락 없이 동시성 보장
  • 단점: 기존 ReportItem 구조와 분리 → 리팩토링 비용 큼

2. Redis Lua Script

  • 구조: JSON 수정 포함 모든 작업을 Lua 스크립트로 작성해 Redis에서 원자적 실행
  • 장점: 완전한 atomic 처리, JSON 구조 유지 가능
  • 단점: Lua 디버깅/관리 복잡, 유지보수 어려움

3. Redis CAS 패턴 (WATCH / MULTI / EXEC)

  • 구조: WATCH로 key 감시, 다른 클라이언트가 key 변경 시 EXEC 실패 → 재시도
  • 장점: Redis native 방식으로 낙관적 락 구현
  • 단점: 재시도 로직 필요, 실패 가능성 존재, 구현 난이도 높음

4. SessionCallback + MULTI/EXEC

  • 구조: Spring Data Redis에서 여러 Redis 연산을 하나의 트랜잭션 블록으로 묶음
  • 장점: 간단한 Redis 연산 원자 처리 가능
  • 단점: 분산 환경에서의 충돌 방지 불가능, WATCH 없음 → 완전한 충돌 방지 어려움

5. Redisson 분산 락 (최종 선택) ⭐️⭐️⭐️

  • 구조: RLock lock = redissonClient.getLock("lock:report:{id}") → 락 획득 후 JSON 수정 → 저장 → 락 해제
  • 장점
    • JSON 캐시 구조 유지 가능
    • 멀티 인스턴스 간 동시성 완벽 보장
    • 락 TTL/재시도 구성 가능
    • 구현이 직관적이고 재사용 용이
  • 단점
    • 약간의 성능 오버헤드 (락 획득/해제)
    • 락 TTL 설정 실수 시 데드락 위험

 

한 눈에 기술 비교

전략 특징 특징 원자성  분산 환경 적합성 유지보수
HINCRBY 수치 필드 분리 ❌ (구조 분리)
Lua Script Redis 내부 처리 ❌ (복잡)
CAS (WATCH) 낙관적 락 ⚠️ (재시도 필요)
SessionCallback Redis 트랜잭션
Redisson RLock 비관적 락

최종 선택: Redisson 분산 락

이유 상세
구조 호환성 ReportItem JSON 구조 변경 없이 사용 가능
구현 난이도 직관적이고 Spring Boot + Redisson에서 쉽게 구현
동시성 보장 멀티 인스턴스 환경에서도 안정성 확보
유지보수 다른 캐시 항목에도 동일한 패턴 적용 가능
확장성 향후 TTL 관리, lock timeout 등 쉽게 확장 가능

 

결론

👉 Redisson 분산 락은 구조 변경 없이도 높은 안정성과 일관성을 확보할 수 있는 가장 현실적인 전략이다.

  • Race condition 방지
  • JSON 캐시 일관성 유지
  • 코드 가독성 및 유지보수 용이
  • 멀티 인스턴스 환경에서 강력한 동시성 제어

 

끝.