point-live-young/decisions/ADR-012 포인트 만료 전략 선택.md at main · f-lab-edu/point-live-young
대규모 사용자와 대용량 트래픽을 안정적으로 처리하는 포인트 기반 이커머스. Contribute to f-lab-edu/point-live-young development by creating an account on GitHub.
github.com
이번에는 다른 질문을 마주했다.
포인트 만료는 언제, 어떻게 처리해야 하는가?
처음 설계는 단순했다.
"매분 스케줄러를 돌려서 만료된 포인트를 일괄 처리하자."
하지만 다시 생각해보니 문제가 보이기 시작했다.
기존 설계: 매분 스케줄링 방식
기존 설계는 아래와 같다.
- 매분 배치 스케줄러 실행
- 전 사용자 포인트 중 만료 대상 UPDATE
- 상태 반영
이 방식은 직관적이고 이해하기 쉽다.
하지만 트래픽과 데이터가 증가하면 상황이 달라진다.
예상되는 문제
- 주기적인 대량 UPDATE 발생
- DB 경합 및 행 잠금 증가
- I/O 부하 상승
- 전체 서비스 성능 저하 가능성
그리고 더 중요한 문제가 있었다.
사용자 화면과 실제 만료 시점 사이의 미세한 시차
예를 들어 포인트가 12:00에 만료되었지만
스케줄러가 12:01에 실행된다면
그 1분 동안은 이미 만료된 포인트가 화면에 노출될 수 있다.
이건 작은 차이지만, 사용자 입장에서는
“만료되었다고 떠야 할 포인트가 남아있는” 이상한 경험이 된다.
고려한 대안들
1️⃣ 조회 시 만료 처리
사용자가 포인트를 조회할 때
해당 유저의 만료된 포인트만 UPDATE 처리한 뒤
최신 상태를 반환하는 방식이다.
장점
- 조회 시점 기준 즉시 일관성 확보
- 대량 배치 부하 제거
- 실패해도 조회 자체는 가능
- 구현 단순
단점
- GET 요청에서 UPDATE 발생 → REST 원칙 위배
- 트래픽 증가 시 조회 부하 증가 가능성
- 대량 만료 시 응답 지연 가능
2️⃣ 메시지 큐 기반 비동기 처리
포인트 만료 이벤트를 메시지 큐에 적재하고
별도의 컨슈머가 비동기로 만료 처리.
장점
- API와 만료 로직 완전 분리
- 대량 처리에 적합
- 재시도 및 복구 용이
단점
- 인프라 복잡성 증가
- 이벤트 유실/중복 처리 위험
- 지연 발생 시 즉각적 일관성 확보 어려움
3️⃣ TTL(Time-To-Live) 기반 자동 만료
Redis 또는 TTL을 지원하는 DB 활용.
장점
- 자동 만료 처리
- 읽기 시 UPDATE 불필요
단점
- 현재 DB 미지원
- Redis 사용 시 영속성/정합성 문제
- 동기화 로직 추가 필요
최종 선택: 조회 시 만료 처리
최종적으로 조회 시 만료 처리 방식을 선택했다.
왜 이 선택을 했는가?
- 즉각적인 일관성 확보
- 사용자가 보는 화면이 항상 최신 상태여야 한다.
- 현재 트래픽 규모 고려
- 단기적으로는 데이터가 많지 않음.
- 운영 복잡성 최소화
- 메시지 큐 도입은 현재 단계에서 과도함.
- DB 지원 제약
- TTL 기능 부재.
결국 이 결정은
“이상적인 구조”가 아니라
“현재 상황에서 가장 합리적인 선택”이다.
구현 방식
GET /api/user-points 호출 시 다음 흐름으로 처리한다.
- 해당 유저의 만료 포인트 UPDATE
- UPDATE 중 에러 발생 시 로깅
- 포인트 조회 정상 수행
- 최신 상태 반환
즉,
읽기 요청이지만, 내부적으로는
해당 유저 범위 내에서 정합성을 맞춘 뒤 응답한다.
트레이드오프
장점
- 사용자 화면에서 만료 즉시 반영
- 매분 대량 스케줄러 제거
- 가용성 유지
- 로그 기반 추적 가능
단점
- REST 원칙 일부 위배
- 조회 트래픽 증가 시 성능 저하 가능
추후 확장 방향
추후 데이터/트래픽 증가 시 다음을 고려할 수 있다.
- 메시지 큐 기반 비동기 만료 처리 전환
- TTL 지원 DB 도입 검토
- 실패 데이터 적재 및 재처리 체계 구축
- 만료 처리 시간/실패율/응답 시간 모니터링
이 전략은 영구적인 선택이 아니라, 단계적인 선택이다.
정리하며
이 글에서 남기고 싶은 메시지는 이것이다.
설계는 “정답”을 찾는 과정이 아니라
현재 상황에서 가장 합리적인 타협을 선택하는 과정이다.
포인트 만료 전략 역시
성능, 일관성, 운영 복잡성 사이에서
균형을 고민한 결과였다.
'나의 개발 이야기' 카테고리의 다른 글
| [Point-live-young (4)] 상품 재고 동시성 문제와 락 전략 선택 (0) | 2026.02.11 |
|---|---|
| [Point-live-young (2)] 만료 우선 차감(Early Expiry First) 알고리즘 설계 (0) | 2026.02.10 |
| [Point-live-young (1)] 포인트 기반 결제 도메인 설계 (0) | 2026.02.10 |
| 개발자로서의 가치관 - 함께, 그리고 긍정적인 영향 (3) | 2025.06.09 |
| 개발자로의 전향 (2) - 개발은 삶과 닮아 있다 (0) | 2025.06.02 |