본문 바로가기

사이드 프로젝트/결제 시스템

결제 시스템 개발 프로젝트 - 1

안녕하세요.

이번 글에서는 결제 시스템 개발을 위해 관련된 주제에 대해 학습하고 내용을 정리하였습니다.

학습을 위해 참고한 링크는 아래와 같습니다. 결제 시스템에 대한 전체적인 프로세스와 네이버 페이에서 제공하는 결제 시스템에 대해서 정리한 내용을 설명하도록 하겠습니다.

 

 

11장. 결제 시스템

결제 시스템이란?위키백과에 따르면 "금전적 가치의 이전을 통해 금융 거래를 정산하는데 사용되는 모든 시스템"이다.1단계: 설계 범위1. 기능 요구사항대금 수신(pay-in) 흐름: 결제 시스템이 판

jm-baek.tistory.com

 

 

네이버페이 개발자센터

응답 예 Response HTTP/1.1 200 OK { "code": "Success", "message": "", "body": { "businessNo": "2208162517", "differenceResults": [{ "differenceRequestId": "DR201810300000008013", "payHistId": "20181113NP1000488732", "orderNo": "TEST001", "sequence": "00"

developers.pay.naver.com

 

 

웹훅(Webhook) 연결하기 | 토스페이먼츠 개발자센터

토스페이먼츠 결제, 브랜드페이, 지급대행 상태에 변경사항이 있을 때 웹훅으로 실시간 업데이트를 받아보세요.

docs.tosspayments.com

 

1. 결제 시스템 프로세스

결제 시스템은 아래 3가지가 핵심적인 포인트라고 판단하였고, 이를 만족하기 위한 프로세스를 설계하는 것이 바람직하다고 생각했습니다.

  • 중복 결제를 막을 수 있는 방법은 무엇인가?
  • 가맹사에서 결제 이벤트 및 결제 주문 데이터를 어떻게 관리할 것인가? 예를 들어, 결제 이벤트 및 주문 데이터가 유실되지 않고 단계별로 데이터베이스에 관리되도록 만들기 위한 방안은 무엇인가?
  • 결제 성공, 실패 등의 결과를 가맹사가 수신에 실패한다면, 이에 대해 어떻게 대응할 것인가?

 

'가상 면접 사례로 배우는 대규모 시스템 설계 2'를 참고하여 정리하신 위 블로그의 내용을 참고하여 결제 시스템을 아래의 프로세스로 설계하였습니다.

 

결제 시스템 프로세스

 

1번부터 5번까지, 그리고 파란색 글씨로 표시된 6번 ~ 7번이 각각 하나의 요청으로 구성됩니다. 이에 대한 자세한 설명은 아래와 같습니다.

  • 1번 ~ 5번
    • 사용자가 결제 시작을 위해 가맹점으로 결제 시작 요청을 보내는 단계입니다.
    • 사용자가 가맹사로 결제 이벤트 및 주문 관련 정보를 포함하여 POST 요청을 전송합니다.
    • 가맹사는 결제 이벤트 및 주문을 데이터베이스에 저장 후, 결제사에 결제 요청을 POST로 전송합니다.
    • 결제사는 가맹사에 결제 토큰(PaymentToken)을 반환합니다. 결제 토큰은 결제 건을 식별하기 위한 키로 사용됩니다.
    • 가맹사는 결제 토큰(PaymentToken)을 저장한 후, 결제 진행 페이지로 Redirect 합니다.
  • 6번 ~ 7번
    • 사용자는 결제사로 결제 토큰(PaymentToken)과 결제 정보(카드 정보 등)을 포함하여 POST 요청을 합니다.
    • 결제사는 이를 통해 결제 승인, 실패, 대기, 취소 등의 처리를 한 후, 결제 종료를 나타내는 페이지로 Redirect 합니다.
    • 또한, 웹훅을 통해 가맹사가 등록한 RedirectURL로 결제 처리 결과를 전송합니다.

위 프로세스가 결제 시스템의 3가지 핵심을 어떻게 만족하고 있는지 하나씩 정리해보면 다음과 같습니다.

  • 중복 결제를 막을 수 있는 방법은 무엇인가? : 멱등키를 활용하여 중복 결제가 불가능 하도록 합니다. 가맹사 시스템은 멱등키를 Primary Key로 활용해 결제 이벤트와 결제 주문을 데이터베이스에 등록함으로써 중복 처리가 되지 않도록 만들 수 있습니다.
  • 가맹사에서 결제 이벤트 및 결제 주문 데이터를 어떻게 관리할 것인가? 예를 들어, 결제 이벤트 및 주문 데이터가 유실되지 않고 단계별로 데이터베이스에 관리되도록 만들기 위한 방안은 무엇인가? : 결제 상태 변경이 발생할 때 마다 이를 데이터베이스에 저장합니다. 예를 들어, 사용자가 결제 시작 요청을 하는 시점에 가맹사의 데이터베이스에 NOT_STARTED라고 상태를 저장하고, 결제 등록이 완료된 시점에는 EXECUTING 이라고 저장합니다. 이를 통해 결제 상태 관리가 가능합니다.
  • 결제 성공, 실패 등의 결과를 가맹사가 수신에 실패한다면, 이에 대해 어떻게 대응할 것인가? : 조정을 통해서 가맹사에 저장된 원장과 결제사로부터 전달 받은 원장이 동일한지 비교하여 필요하다면 수동으로 처리합니다. 또한, 재시도 큐를 활용하여 가맹사의 판단 하에 결제사로 결제 재시도 요청을 보낼 수 있습니다.

 

2. 네이버페이 결제 시스템 연동

위에서 정리한 내용을 바탕으로, 이번에는 네이버페이에서 제공하는 결제 시스템 연동 방법과 위와 비교하여 좀 더 심층적으로 파악하고자 했습니다. 네이버페이에서는 Javascript SDK를 통해 결제 연동 기능을 제공하고, 이와 연동하기 위한 결제 프로세스는 아래와 같이 설계했습니다. (혹시라도 잘못 이해한 점이 있다면 지적해주시면 감사하겠습니다...)

네이버페이 결제 프로세스

 

기존 결제 시스템 설계와의 가장 큰 차이점은 PaymentId에 있었습니다. 1번 설계에서는 PaymentId가 결제 화면이 호출되기 이전에 가맹사 시스템 - 결제사 시스템 사이의 요청 - 응답을 통해서 발행되었지만, 네이버 페이에서는 PaymentId가 결제 화면에서 결제 요청이 네이버페이 시스템으로 전송되어 처리 되는 시점에 이를 발행합니다.

 

이 케이스가 처음에는 다소 의아하긴 했습니다. 왜냐하면, 가맹점 시스템은 paymentId를 Redirect GET의 쿼리 파라미터로 전달 받을 수 밖에 없고, GET 요청은 SAFE Method이기 때문에 이를 결제 이벤트 및 주문 정보를 저장에 사용하는 것이 과연 표준 방식인지에 대한 의문이 있었습니다. 그래서, RFC의 HTTP Safe Method에 대한 내용을 다시 확인했습니다. RFC의 Safe Method 관련 내용은 아래와 같았습니다.

  • Safe 메소드를 보내는 클라이언트는 본인의 요청이 서버 상태에 영향을 주지 않는 것을 기대한다.
  • 물론, Safe 메소드 자체가 로그 기록 등의 부수적인 동작으로 인한 서버 상태 변경까지는 막을 수는 없다. 
  • 그러므로, Safe 메소드를 요청하는 클라이언트는 로그 기록과 같은 부수적인 동작에 영향을 줄 수 없어야 하고, 서버 측에서 자체적으로 실행하는 부수적인 동작에 대해서는 책임을 지지 않는다.
  • RequestParam을 포함할 수 있도록 Safe 메소드가 설계 되었다면, Safe하게 동작할 수 있도록 책임을 져야 한다.
  • safe 및 unsafe 메소드를 구별하는 이유는 캐싱, 웹 크롤링 등이 서버에 부작용을 일으키지 않고 사용하도록 하기 위함이다.

위 원칙을 따라 네이버페이와 연동하기 위해서는 가맹점 결제 서비스는 아래와 같이 프로세스를 만들 수 있습니다.

  • RedirectURL을 통해서 paymentId를 GET 요청으로 받는다. 그리고, '결제 대기 중'과 같은 페이지로 다시 Redirect 한다.
  • '결제 대기 중' 페이지에서는 Polling 등의 방식으로 결제 결과를 가맹점 서버로 부터 응답 받을 수 있도록 대기한다.
  • 그러므로, RedirectURL 자체는 항상 '결제 대기 중' 페이지를 호출하는 것이므로 상태를 변경하지 않는 Safe 메소드이다.
  • 이와는 별개로, 비동기 작업 등을 통해 paymentId를 Key로 활용해 가맹점 시스템에 결제 이벤트 및 주문 상태를 기록하고, 네이버페이로는 결제 승인 요청을 전송한다.
    • 해당 동작을 Safe 메소드 내의 부수적인 동작으로 간주하고, 해당 동작에 대해서는 결제 시스템이 전적으로 책임을 져야한다.
    • 결제 이벤트 주문 상태 기록, 네이버페이로의 결제 요청이 멱등하게 실행될 수 있도록 PaymentId를 활용한다.
  • 결제 승인 요청에 대한 응답을 결제 이벤트 및 주문 상태로 기록하고 작업을 종료한다.
  • '결제 대기 중' 페이지는 Polling 등의 방법으로 결제 결과를 확인할 수 있다.

위의 방법으로도 결제 시스템의 핵심적인 내용을 만족하며 설계가 가능함을 알 수 있었습니다. 

 

 

이처럼, 결제 시스템에 필요한 핵심적인 기능(멱등성, 결제 이력 저장, 결제 실패 대응 방법 등)만 정상적으로 구현할 수 있다면, 여러가지 패턴의 설계도 가능함을 알 수 있었습니다. 네이버페이 연동 방법은 1번의 요청으로 모든 결제 프로세스가 진행된 점에서 네트워크 비용을 줄일 수 있다는 장점도 있고, 하나의 결제 건에 대해서 로그도 비교적 시간 순서로 남기 때문에 분석에 편리함이 있을 것이라고 판단했습니다.

 

다음 편에서는 1번의 방식으로 결제 프로세스가 진행되는 시뮬레이션을 구현한 내용을 이어서 설명하도록 하겠습니다.

아래 Github 링크에 소스가 있으며 완료되는 대로 다음 편을 이어서 작성하겠습니다. 감사합니다.

 

https://github.com/chrismrkr/payment-platform 

 

GitHub - chrismrkr/payment-platform: My Payment Platform Exercise

My Payment Platform Exercise. Contribute to chrismrkr/payment-platform development by creating an account on GitHub.

github.com