Introduction
"결제가 완료되었습니다"라는 메시지를 보았는데, 통장에서는 같은 금액이 두 번 빠져나갔다면 어떨까요? 고객의 신뢰를 완전히 잃어버릴 수 있는 이런 악몽 같은 상황은 결제 시스템을 구축하는 모든 개발자의 가장 큰 걱정거리입니다.
매일 수억 달러의 거래를 처리하는 Stripe은 어떻게 이 문제를 해결했을까요? 네트워크 오류, 서버 장애, 타임아웃... 수많은 불확실성 속에서도 단 한 건의 이중 결제도 발생하지 않도록 만드는 기술적 해법이 바로 '멱등성 API'입니다.
오늘은 Stripe의 핵심 아키텍처 중 하나인 멱등성 API의 설계 원리와 구현 방식을 상세히 살펴보겠습니다. 특히 지수 백오프와 지터를 활용한 재시도 메커니즘까지, 대규모 결제 시스템을 안정적으로 운영하기 위한 모든 기술적 노하우를 파헤쳐 보겠습니다. 여러분의 결제 시스템을 한 단계 더 견고하게 만들어줄 핵심 인사이트를 이 글에서 발견하실 수 있을 겁니다. <How Stripe Prevents Double Payment Using Idempotent API> 를 번역해 가져왔습니다.
Stripe가 멱등성 API로 이중 결제를 방지하는 비결
2010년, 미국 캘리포니아한 형제가 사업을 시작하려 했습니다.그러나 온라인 결제 시스템을 구축하는 과정이 너무 복잡했습니다. 그래서 방향을 전환해 온라인 결제 서비스를 만들었고, 이것이 바로 핀테크 스타트업 Stripe의 시작이었습니다.
이중 결제 문제
사용자가 늘어나면서 같은 거래에 대해 실수로 두 번 요금이 청구되는 이중 결제 문제가 발생하기 시작했습니다. 이런 문제가 발생하는 주요 원인은 다음과 같았죠.
1. 서버 오류
서버가 요청을 처리하는 도중 오류가 발생하는 경우입니다.
이때 클라이언트는 해당 요청이 성공적으로 처리되었는지 여부를 알 수 없습니다.따라서 안전하게 재시도할 수 없습니다. 재시도할 경우 동일한 거래에 대해 이중으로 결제가 발생할 수 있기 때문입니다.
2. 네트워크 오류
서버는 요청을 성공적으로 처리했지만, 클라이언트에게 응답을 전송하기 전에 네트워크 연결이 끊어지는 경우입니다.
이런 경우에도 클라이언트는 요청의 성공 여부를 알 수 없습니다. 따라서 안전한 재시도가 불가능하며, 이중 결제의 위험이 있죠.
멱등성 API로 문제 해결하기
Stripe은 이중 결제 문제를 가장 효과적인 방법으로 해결하고자 했습니다. 흔히 그렇듯, 가장 단순한 해결책이 최선이었습니다. 그들이 선택한 해결책은 바로 멱등성 API였죠.
멱등성 API는 동일한 요청을 여러 번 시도해도 부작용 없이 안전하다는 것을 보장합니다. 즉, 같은 요청을 여러 번 전송하더라도 실제로는 단 한 번만 처리된다는 의미입니다.
Stripe의 멱등성 API 구현 방식은 다음과 같습니다:
1. 멱등성 키 활용
이미 처리된 요청은 다시 처리하지 않아야 합니다. 이를 위해서는 서버가 처리한 요청을 추적할 수 있어야 합니다.Stripe은 이를 위해 고유한 문자열(UUID)을 멱등성 키로 사용합니다.이 키는 모든 요청의 HTTP 헤더에 포함됩니다. 요청 내용이 변경될 때마다 새로운 UUID가 생성됩니다. 멱등성 키는 마치 지문처럼 특정 요청이 이미 처리되었는지 확인하는 역할을 합니다.
서버는 인메모리 데이터베이스에 이 멱등성 키들을 저장합니다. 요청이 성공적으로 처리되면 해당 응답도 캐시에 저장됩니다. 새로운 요청이 들어오면 먼저 인메모리 데이터베이스를 조회합니다. 처음 받은 요청일 경우에만 처리하고 해당 멱등성 키를 데이터베이스에 저장합니다. 이미 처리된 요청이라면 캐시에 저장된 응답을 반환합니다.
서버 오류가 발생하면 ACID 특성을 가진 데이터베이스를 통해 트랜잭션을 롤백합니다. 멱등성 키는 24시간 후 인메모리 데이터베이스에서 자동으로 삭제됩니다. 이는 저장 공간을 효율적으로 관리하면서도 실패한 요청을 재시도할 충분한 시간을 제공합니다.
즉, 24시간이 지나면 같은 멱등성 키를 재사용할 수 있게 됩니다.
2. 실패한 요청에 대한 재시도(Retry)
멱등성 키를 사용하면 안전한 재시도가 가능하지만, 다수의 동시 요청으로 인한 서버 과부하 위험이 있습니다.
이를 해결하기 위해 지수 백오프(exponential backoff) 알고리즘을 사용합니다. 이는 요청이 실패할 때마다 클라이언트가 재시도 전에 점진적으로 더 긴 대기 시간을 갖는 방식입니다.
또한, 서버 장애 상황에서 많은 클라이언트가 동시에 재접속을 시도하는 '쏠림 현상(thundering herd)'이 발생할 수 있습니다. 이를 방지하기 위해 지터(jitter)를 적용하여 각 클라이언트의 재시도 대기 시간에 무작위성을 부여합니다.
멱등성은 안정적인 온라인 결제 시스템의 핵심 요소입니다.이는 보안성 강화와 사용자 경험 개선에도 크게 기여합니다. 이러한 기술력을 바탕으로 Stripe은 현재 세계 최고의 온라인 결제 서비스 중 하나로 자리매김하고 있습니다.
👥 더 나은 데브필을 만드는 데 의견을 보태주세요
Top 1% 개발자로 거듭나기 위한 처방전, DevPill 구독자 여러분 안녕하세요 :)
저는 여러분들이 너무 궁금합니다.
어떤 마음으로 뉴스레터를 구독해주시는지,
어떤 환경에서 최고의 개발자가 되기 위해 고군분투하고 계신지,
제가 드릴 수 있는 도움은 어떤 게 있을지.
아래 설문조사에 참여해주시면 더 나은 콘텐츠를 제작할 수 있도록 힘쓰겠습니다. 설문에 참여해주시는 분들 전원 1개월 유료 멤버십 구독권을 선물드립니다. 유료 멤버십에서는 아래와 같은 혜택이 제공됩니다.
- DevPill과의 1:1 온라인 커피챗
- 멤버십 전용 슬랙 채널 참여권
- 채용 정보 공유 / 스터디 그룹 형성 / 실시간 기술 질의응답
- 이력서/포트폴리오 템플릿
의견을 남겨주세요