본문으로 건너뛰기
Advertisement

실전 고수 팁 — 대규모 시스템의 API 버전 교체 전략과 멱등성(Idempotency) 방어

단순한 REST API 연동을 넘어서, 월 백만 건의 결제를 처리하는 엔터프라이즈 서버 아키텍처에서 반드시 지켜야 하는 규칙들을 배웁니다.

1. API 버저닝 전략 (Versioning)

구형 앱(모바일, 레거시 시스템)과 새로 업데이트된 클라이언트가 서버를 동시에 호출할 때, 무턱대고 API 응답 필드 제원을 변경하면 구형 클라이언트들은 치명적인 에러(앱 직사)를 맞이합니다.

실무에서 채택하는 버저닝 3대 기법은 다음과 같습니다.

  1. URI Versioning: /api/v1/users, /api/v2/users (가장 직관적이고 널리 쓰임)
  2. Request Parameter Versioning: /api/users?version=2 (거의 쓰지 않음)
  3. HTTP Header Versioning (Media Type): Accept: application/vnd.myname.v2+json (REST 철학에 가장 부합하지만 테스터/프론트엔드단에서 호출하기 매우 복잡함)

실제 대기업 백엔드 전환 사례에서 가장 실패율이 적고 관리가 쉬운 방법은 URI Versioning입니다. 이를 위해 최적화된 스프링 라우터 패키지를 분리합니다: com.app.api.v1.UserController, com.app.api.v2.UserController

2. 멱등성(Idempotency) 키 설계와 재시도 방어

모바일 네트워크 환경 등에서 통신이 지연될 때, 클라이언트는 서버가 요청을 받았는지 모르고 타임아웃이 발생하여 "결제(POST) 버튼을 2번 연속 누르는" 사고가 흔히 발생합니다. 동일한 요청을 여러 번 보내도 서버 상태가 동일하게 유지되는 성질을 멱등성이라 합니다.

  • GET, PUT, DELETE는 스펙상 자연스럽게 멱등하지만, POST는 멱등하지 않습니다 (매번 새로운 주문/결제 레코드 생성).

해결책: Idempotency-Key 시스템 설계 서버는 클라이언트가 헤더에 보낸 Idempotency-Key (UUID 등)를 Redis 캐시에 임시 저장하고, 24시간 내 동일한 키로 POST 요청이 들어오면 로직을 다시 수행하지 않고 캐싱해 둔 첫 번째 성공 응답을 그대로 반환해야 합니다.

@PostMapping("/pay")
public ResponseEntity<PaymentResponse> pay(
@RequestHeader("Idempotency-Key") String idempotencyKey,
@RequestBody PaymentRequest req) {
// 1. Redis에서 키 유무 검증
if (redisService.exists(idempotencyKey)) {
return ResponseEntity.ok(redisService.get(idempotencyKey));
}
// 2. 결제 로직 처리
PaymentResponse res = paymentService.process(req);
// 3. Redis 저장 (TTL 24h)
redisService.save(idempotencyKey, res);

return ResponseEntity.ok(res);
}

3. WebClient 등 외부 통신 시 서킷 브레이커와 타임아웃

스프링 서버가 다른 외부 마이크로서비스(혹은 PG사) API를 호출할 때 상대편 서버가 죽어서 30초 대기(Timeout)에 걸리면 어떻게 될까요? 우리 서버의 톰캣 스레드들도 모두 그 응답을 기다리다가 마비(Thread 고갈)되어 우리 서버마저 연쇄적으로 다운됩니다(Cascading Failure).

  1. RestClientWebClient를 빈(Bean)으로 등록할 때 반드시 Connection Timeout(예: 3초)과 Read Timeout(예: 5초)을 수동으로 짧게 세팅하세요. (기본값은 무제한이거나 OS 종속적입니다).
  2. 장애 발생 시 빠르게 예외를 던지고 Fallback 응답(예: "현재 시스템 지연 중입니다")을 내보내 스레드를 즉각 해제하도록 유도하는 Resilience4j(서킷 브레이커) 패턴을 전격 입혀야 합니다.
Advertisement