[TIL] 드랍 조회수 집계 최적화 (Redis 중복 방지 + DB 원자 증가)

김재진·2026년 5월 11일

내일배움캠프

목록 보기
68/70

오늘의 한 줄

드랍 조회수는 애플리케이션 메모리 카운팅 대신 Redis 중복 방지 키(SETNX + TTL)DB 원자 증가 쿼리를 결합해, 고트래픽에서도 중복 카운트를 억제하고 DB 업데이트 부하를 줄였다.


문제 상황

드랍 상세 페이지는 오픈 직전/직후 트래픽이 몰리며, 같은 사용자의 반복 조회가 많다.
요청마다 DB view_count를 증가시키면:

  • 동일 사용자 중복 카운트
  • DB 업데이트 트래픽 급증
  • 집계 정확도 저하 + DB 부하 증가

적용한 방식

1) Redis로 중복 조회 차단 (SETNX + TTL)

  • 키 형식: drop:view:{dropId}:{viewerIdentifier}
  • viewerIdentifier:
    • 로그인 사용자: email
    • 게스트: ip + userAgent를 SHA-256 해시
  • setIfAbsent(key, "1", TTL) 성공 시에만 "첫 조회"로 간주

현재 TTL 값: dropshop.drops.view-count-ttl-seconds = 600 (기본 10분)
즉, 기본 설정에서는 동일 식별자가 10분 내 재조회해도 1회만 카운트된다.

2) DB는 원자 증가 쿼리로 반영

엔티티를 로드/저장하지 않고 원자 쿼리로 직접 증가:

update Drops d
set d.viewCount = d.viewCount + 1
where d.id = :dropId

읽기-수정-쓰기 경쟁을 줄이고 DB 부하를 낮춘다.

3) 실패 시 롤백 처리

흐름은 다음과 같다:

① Redis SETNX 성공
② DB 증가 쿼리 수행
③ DB 증가 실패 시 → catch 블록에서 Redis 키 delete 수행 (수동 롤백)

즉, Redis 롤백은 트랜잭션 이벤트 리스너가 아니라 예외 처리(catch) 기반 수동 delete로 처리한다.

3-1) 정합성 주의사항

  • DB 업데이트는 @Transactional 범위에서 수행
  • Redis 키 생성/삭제는 외부 시스템 연산
  • 두 작업은 분산 트랜잭션(2PC)이 아니므로, 극단적 장애 상황에서는 일시적 불일치 가능성이 남는다.
    • 예: DB 증가 실패 후 Redis delete도 실패하면, TTL 만료 전까지 과소집계 가능

4) Redis 장애 시 정책

현재 구현은 Fail-Close에 가깝다.
Redis 처리(SETNX)에서 예외 발생 시:

  • 경고 로그 기록
  • 조회수 증가 자체를 수행하지 않음 (DB 업데이트 skip)
내용
장점중복 폭주/오염 카운트 방지
단점Redis 장애 구간에서 조회수 과소집계 가능

트레이드오프

  • TTL이 길수록 중복 억제는 강해지지만 재방문 반영이 느려질 수 있음
  • TTL이 짧을수록 집계 민감도는 올라가지만 중복 억제 효과가 약해질 수 있음
  • 게스트 식별(ip + userAgent)은 NAT/프록시/공용PC 환경에서 완전 식별이 어려운 Best-effort 방식이다

다음 개선 아이디어

  • Redis 장애 시 운영 정책을 명시적으로 분기 (Fail-Close 유지 vs 조건부 Fail-Open)
  • 중복 차단율/증가 성공률/롤백 실패율 메트릭 대시보드화
  • TTL A/B 테스트로 서비스 특성에 맞는 최적 구간 탐색
profile
개발공부 처음해보는 사람

0개의 댓글