Table of Contents
Spring Boot – 멱등성(Idempotency)과 멱등키 활용하기
네트워크 오류로 인해 결제 요청이 두 번 가거나, 실수로 버튼을 여러 번 클릭해서 중복 주문이 발생한 적이 있나요? 이러한 문제를 우아하게 해결해 주는 핵심 기술이 바로 멱등키(Idempotency Key)입니다.
1. 멱등성(Idempotency)이란?
멱등성이란 연산을 여러 번 적용하더라도 결과가 달라지지 않는 성질을 의미합니다.
- 수학적 예시: 어떤 수에 1을 곱하는 연산은 여러 번 반복해도 결과가 같습니다.
- HTTP 메서드 예시: *
GET,PUT,DELETE는 기본적으로 멱등성을 가집니다. POST는 호출할 때마다 새로운 리소스를 생성할 수 있으므로 기본적으로 비멱등(Non-idempotent)합니다.
2. 멱등키(Idempotency Key)의 역할
POST와 같이 비멱등한 요청을 안전하게 처리하기 위해 클라이언트는 요청 헤더에 유니크한 값(UUID 등)을 담아 보냅니다. 서버는 이 키를 확인하여:
- 처음 본 키라면: 요청을 정상 처리하고 결과를 저장합니다.
- 이미 처리된 키라면: 실제 로직을 수행하지 않고 저장된 결과(응답)를 그대로 반환합니다.
3. Spring Boot에서 멱등키 구현하기
Spring Boot 환경에서 멱등키를 구현하는 가장 효율적인 방법은 Redis와 Interceptor를 활용하는 것입니다.
A. 기술 스택
- Redis: 분산 환경에서 키를 빠르게 조회하고 만료 시간(TTL)을 설정하기에 적합합니다.
- HandlerInterceptor: 컨트롤러에 진입하기 전 멱등키를 검사합니다.
B. 흐름도
- 클라이언트가
Idempotency-Key를 헤더에 담아 요청. - 서버(Interceptor)가 Redis에서 해당 키 존재 여부 확인.
- Key 없음: Redis에 키 저장 (Status:
PROCESSING) -> 비즈니스 로직 수행 -> 결과 저장 및 반환. - Key 있음: *
PROCESSING중이면 "처리 중" 에러 반환.- 완료된 상태면 저장된 응답값 반환.
C. 주요 코드 예시
1. Redis 설정 및 로직 (Pseudo Code)
@Component
@RequiredArgsConstructor
public class IdempotencyService {
private final RedisTemplate<String, Object> redisTemplate;
public boolean isFirstRequest(String key) {
// SETNX (Set if Not Exists)를 사용하여 원자적 체크
return redisTemplate.opsForValue()
.setIfAbsent(key, "PROCESSING", Duration.ofMinutes(10));
}
public void saveResponse(String key, Object response) {
redisTemplate.opsForValue().set(key, response, Duration.ofMinutes(60));
}
}
2. Interceptor 구현
@Component
@RequiredArgsConstructor
public class IdempotencyInterceptor implements HandlerInterceptor {
private final IdempotencyService idempotencyService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String idempotencyKey = request.getHeader("Idempotency-Key");
if (idempotencyKey == null) return true; // 필수가 아니라면 통과
if (!idempotencyService.isFirstRequest(idempotencyKey)) {
// 이미 존재하는 키라면 중복 요청 처리 (409 Conflict 또는 기존 응답 반환)
response.setStatus(HttpServletResponse.SC_CONFLICT);
return false;
}
return true;
}
}
4. 도입 시 주의사항
- 키의 범위: 유저 ID와 멱등키를 조합하여 키를 생성하는 것이 안전합니다. (다른 유저와 키가 겹칠 확률 방지)
- 만료 시간(TTL): 멱등키를 무한히 저장할 수는 없으므로, 비즈니스 특성에 맞춰(예: 24시간) 적절한 유효 기간을 설정해야 합니다.
- 성공/실패 케이스: 비즈니스 로직이 실패했을 경우, 멱등키를 삭제하여 재시도할 수 있게 할지 아니면 실패 기록을 남길지 정책을 정해야 합니다.