본문 바로가기
Loopers

WIL - 9주차 회고

by Soono991 2025. 9. 12.

Redis를 "캐시"가 아닌 "저장소"로 바라보기

이번 주에는 상품 랭킹 기능을 구현하면서 Redis를 단순한 결과 캐시가 아니라 랭킹 전용 데이터베이스로 활용했다.
ZSET의 정렬 특성 덕분에 추가 연산 없이 Top-N, 순위, 점수를 바로 조회할 수 있었고, 이는 실시간성과 고동시 동접 처리 요구에 적합했다.

배치 리스너 + Zip-Map-Sink

메시지를 단건으로 처리하면 동일 상품에 대한 반복 업데이트로 불필요한 쓰기가 발생한다.
이를 개선하기 위해 배치 리스너를 도입했고, 배치 내 이벤트를 상품 단위로 집계(Zip), 가중치 점수로 변환(Map), 최소 연산으로 저장(Sink) 하는 패턴을 적용해 효율을 높였다.

집계 책임의 분리: Metrics vs. Rank

product_metrics 집계와 product_rank 집계를 같은 컨슈머에서 처리하면 장애 전파와 코드 결합도가 높아진다.
컨슈머를 분리해 단일 책임 원칙(SRP)을 지켰고, 각 파이프라인이 독립적으로 장애 대응·확장·운영되도록 했다.

가중치 설계: 수학적 최적화가 아닌 비즈니스 정합성

조회(0.1)·좋아요(0.3)·판매(0.7)의 가중치는 신호 강도, 희소성, 조작 난이도, 서비스 목표를 기준으로 정했다.
판매는 전환을 직접 반영하므로 가장 높은 가중치를 두었고, 변동성과 조작 가능성이 큰 조회는 낮췄다.
또한 판매 스코어에는 로그 함수를 적용해 값의 편차를 완화했다.

Carry-Over 전략: 연속성과 최신성의 균형

데이터가 희소한 구간에서 랭킹이 공백으로 보이지 않도록, 이전 주기의 상위 N 데이터를 **정규화 계수(예: 1%)**를 적용해 반영했다.
이 방식은 과거 데이터가 현재를 압도하지 않으면서도 랭킹의 연속성을 보장했다.

TTL 보정: Duration이 아닌 Anchor Time 기반 만료

Carry-Over 실행 시각을 TTL 기준으로 삼으면 만료 시각 불일치로 공백이 생길 수 있다.

이를 막기 위해 일 단위는 정오 기준 +2/3일 자정, 시간 단위는 30분 반올림 등 고정 기준(anchor)을 적용해 TTL을 계산했다.

TTL은 단순한 시간 설정이 아니라 운영 스케줄과 정렬된 정책이어야 한다.

백업 전략: 상위 N 스냅샷

TTL 만료 이후에도 분석과 회고를 위해 이력이 필요하다. 하지만 모든 랭킹을 저장하는 것은 비용 대비 효용이 낮다.
그래서 일별·시간별 상위 N개(또는 상위 N%)만 정규화된 스냅샷으로 RDB에 보관했다.

앞으로 더 해볼 것들

- 가중치 실시간 조정
현재는 조회·좋아요·판매 가중치를 고정 값으로 두고 있다.
이를 실시간으로 가중치를 조절할 수 있는 기능을 구현해본다.

- Zip-Map-Sink + Redis 파이프라인화
배치 + Zip-Map-Sink로 중복 연산은 줄였지만, 여전히 Redis에 개별 호출이 발생한다.
향후에는 Redis 파이프라인 기능을 활용해 쓰기 연산을 일괄 처리하고 네트워크 RTT를 줄이는 최적화를 적용할 수 있다.

 

'Loopers' 카테고리의 다른 글

Loop:Pak - 10주간의 회고  (0) 2025.09.19
WIL - 8주차 회고  (0) 2025.09.05
WIL - 7주차 회고  (1) 2025.08.29
WIL - 6주차 회고  (1) 2025.08.24
WIL - 5주차 회고  (2) 2025.08.17

댓글