[내가 헷갈려서 정리하는 내용]
결제 시스템을 구축하다 보면, 멱등성과 동시성을 모두 보장해줘야 한다.
위 두가지 개념을 시스템 내에서 왜 보장해야 하는지 그리고 어떻게 보장할 수 있는지 정리해보자.
| 항목 | 멱등성 보장 | 동시성 보장 |
|---|---|---|
| 초점 | 같은 요청이 여러 번 들어오는 것에 대한 처리 | 서로 다른 요청이 동시에 들어오는 것에 대한 처리 |
| 문제 상황 | 네트워크 재전송, 중복 요청 | 여러 사용자/스레드가 같은 자원을 동시에 수정 |
| 목적 | 중복 요청으로 인한 부작용 방지 | 데이터 무결성과 일관성 유지 |
| 예시 | 같은 결제 요청을 여러 번 보내도 1번만 결제됨 | 여러 사용자가 동시에 재고 1개 구매 시 1명만 성공해야 함 |
try {
idempotencyService.reserveKey(idempotencyKey); // INSERT only
} catch (DuplicateKeyException e) {
// 이미 누가 처리 중이거나 완료된 키
return idempotencyService.getResponse(idempotencyKey)
.map(res -> ResponseEntity.ok(res))
.orElse(ResponseEntity.status(409).body("이미 처리 중입니다."));
}
reserveKey 메서드 예시
public void reserveKey(String key) {
IdempotencyEntity entity = new IdempotencyEntity(key, null); // 아직 응답 없음
idempotencyRepository.save(entity); // 중복이면 DuplicateKeyException 발생
}
| 레디스 사용 이유 | 설명 |
|---|---|
| 성능 | Redis는 인메모리 기반 → DB보다 훨씬 빠름 (μs 단위 응답) |
| 부하 분산 | DB에 모든 요청이 몰리면 병목 발생 → Redis로 트래픽 분산 |
| TTL 관리가 쉬움 | Redis 키는 만료시간 설정이 쉬워서 자동 정리 가능 |
| 분산 락 기능 | RedLock 등으로 멀티 인스턴스 환경에서 락 동기화 가능 |
| 비즈니스 응답 저장보다 "락만" 필요할 때 유용 | 응답을 DB에 저장하고, 락만 Redis로 처리하는 패턴도 많음 |
| 유연성 | 다양한 자료구조, Expire 설정, 간단한 pub/sub 기능 등으로 상황별 대응 가능 |
| 항목 | DB 제약조건 (PK 방식) | Redis (락 방식) |
|---|---|---|
| 속도 | 상대적으로 느림 (디스크 기반) | 매우 빠름 (메모리 기반) |
| 복잡도 | 낮음 (INSERT로 충분) | 락 획득/해제 로직 필요 |
| 멀티 인스턴스 대응 | 별도 고려 필요 (DB로는 락 제어 어려움) | RedLock 등으로 쉽게 분산 락 |
| TTL 관리 | 직접 구현해야 함 | 기본 기능으로 지원 |
| 응답 저장 여부 | 대부분 저장함 | 보통은 락만 Redis, 응답은 DB |