강의

멘토링

커뮤니티

인프런 커뮤니티 질문&답변

위고잉업님의 프로필 이미지
위고잉업

작성한 질문수

제미니의 개발실무 - 커머스 백엔드 기본편

코드 느끼기

외부 API 연동 시 데이터 정합성을 고려해야 할 때..

해결된 질문

작성

·

44

1

안녕하세요.

저도 개인 프로젝트로 이커머스를 만들면서, 결제와 같은 외부 API를 호출하는 부분에 대해서 많은 고민을 하게 되는 것 같습니다.

가령, 결제 승인을 위해 PG API를 호출한 이후 결제 내역을 DB에 저장한다던가..
혹은 결제 처리 이후 진행되어야 할 비즈니스 로직(배송 생성, 재고 차감 등..)을 진행해야한다던가..
하지만 외부 API를 호출한다는 것은 사실 비즈니스 로직의 트랜잭션과 묶일 수 없다는 것이 참 어려운 것 같습니다.

PG API 호출에 성공했지만, 이후 비즈니스 로직이 실패된다면 결제 강의 - 코드느끼기에서 말씀해주신 것 처럼,
사용자의 돈은 빠져나갔지만, 배송 처리가 되지 않거나 그런 일이 발생할 수 있을 것 같아요.


혹은 PG API 호출 시에, 타임 아웃이 발생해서 실패했다고 판단했지만, 알고보니 PG 서버 상으로는 승인이 정상적으로 처리 된 경우도 있을 것 같아요.

이처럼 외부 API 연동 시에 데이터 정합성을 고려하는 것이 엄청 어려운 것 같습니다.
그래서 저는 결제처럼 사용자의 돈을 처리해야하는 경우 세부적인 방어 로직이 필요할 것 같다는 생각을 합니다.

그래서 고민을 하면서, 이것저것 찾아보다가 사용하게 된 패턴이 외부 API를 요청하기 전에,
state를 추가해서 관리하자 라는 것이었는데요. 예를 들어 결제로직의 경우 결제 검증을 처리하고 승인 API를 호출하기 전에 Payment의 State를 PENDING_PG_REQUEST(예시)로 변경한 뒤, PG API를 호출하는 흐름입니다. 만약 PG API 호출에 정상적으로 성공했지만, 결제 후처리 비즈니스 로직에 실패했더라도,
스케줄러 같은 걸 통해 특정 시간 동안 계속해서 PENDING_PG_REQUEST인 결제 건이 있다면, 이것은 적어도 PG API를 호출하고 나서, 무언가 잘못되었다는 것이니까, 데이터 정합성을 맞춰주기 위해 한번 더 직접 API를 호출하고 나서 비즈니스 로직을 추가적으로 실행시켜주는 그런 작업을 진행해주면 될 것 같아요.

이런 패턴이 어떻게 보면 강의 코드 예제에서 정산을 처리하는 SettlementService의 transfer 메서드와 비슷하다고 생각합니다. Settlement Entity에 Ready인 데이터를 결국 주기적으로 처리하면서, 언젠가는 정산 처리를 진행하게 되니까요!

근데 문득 제가 사용하는 방식, 그리고 transfer 메서드의 방식은 특정 조건이 충족해야한다는 점이 있는 것 같아요. 사용하는 외부 API가 멱등성을 제공해야하고, 데이터 정합성을 처리하기 위해 돌아가는 스케줄러,배치 또한 자체적으로 중복처리 방지를 방지해야 한다는 것을요...

이렇게 생각하다보니 끝도 없이 딥해지고 복잡해지는 것 같아서, 문득 다시 결제 부분 강의를 보다보니,
수기 처리 방식도 아주 잠깐 언급하셨더라구요.
문제가 발생했을 때 로그를 남겨놔서, 데이터를 비교 후 데이터 정합성을 맞춘다.

근데 돈과 관련된 부분은 그 즉시, 성공 실패에 대한 처리를 해줘야할 것 같기도 하고 이 부분만큼은 과하게 방어 로직을 작성하는 게 맞을까?라는 생각이 들게 되는 것 같아요. 그리고 만약 외부 API가 멱등성을 제공하지 않으면
어떻게 처리해야하지?라는 생각이 들기도 하고요.

재민님께서는, 이런 외부 API 연동과 데이터 정합성을 고려해야할 때 방어 로직을 깊게 생각하시는지 궁금해서 질문을 하게 되었습니다. 근데 사실 돈과 관련된 부분은 아무리 생각해도 많은 방어 로직을 필요로 하는 것은 당연한 것 같긴한데, 어느 정도로 처리를 해줘야할 지 모르겠네요. 하하..
최소한의 방어로직, 그리고 예외, 실패 시 로깅 처리로 모든 가능성을 추적해야 하는 게 효율적일까요??

감사합니다!

답변 1

1

제미니님의 프로필 이미지
제미니
지식공유자

안녕하세요! 질문 감사드립니다! 많은 고민을 하고 계시군요! 아주 바람직한 것 같습니다 😃

말씀해주신 것과 유사하게 고객이 민감하게 반응 할 수 있는 부분최대한 방어로직을 탄탄하게 하는게 좋다고 생각합니다!
(그렇기에 외부 연동사에게 정합성 보정을 위한 API를 개발 요청해야합니다! 저도 숙박 상품외부 서비스에서 연동한 적이 있는데 이쪽에서 재고에 대한 최종적 정합성 API를 주지 않아 PG사 돈은 빠져나갔는데 객실 재고가 없어서 결제가 취소 되어야하는 문제로 고객들 민원이 상당했었습니다, 그때에도 결국 연동사 쪽에서 기능 API를 제공해주는 것으로 풀었었네요)

수기 처리도 언급을 했지만 생각하시는 것 처럼 이슈 대응에 즉시성이 부족하기 때문에 알림/모니터링 관점도 챙겨야하는게 중요한 것 같고, 수기처리만으로는 해결이 어려울 것 같습니다 (고객은 새벽에도 결제를 진행하고.. PG사 장애로 대량건이 발생하는 등등..)

그치만 현실과 비즈니스적으로 생각해볼 부분은 고객이 불쾌함(강성민원 및 서비스 이탈로 변환 가능한)을 느낄 수 있는 영역최소화 하는 것에 집중하는게 좋다고 생각합니다

그래서 최~대한 민감한 외부 API를 호출하기 전에 모든 준비를 끝내놓고 호출하는게 좋다고 생각합니다

추가적으로 그럼에도 외부 시스템 장애가 발생 할 수 있으니 그에 대한 처리는 적어주신 것 처럼 별도 보정 배치 같은 것을 만들어주는게 가장 기본적이면서도 운영 효율을 올리는 작업 같습니다 😃
(보정 배치가 있어도 운영을 위해 로깅 / 알람은 필수겠죠ㅎㅎ)


사설이 좀 길었나 싶은데 어느 정도로 방어 로직을 구성 할 것인가? 대한 것에 대해 기준을 잡을때 저는 아래 같은 관점을 생각합니다

  • 방어 로직은 소수의 문제 케이스를 막아주는 최종 수비수 역할을 해야한다

    • 방어로직이 돌아야하는 건 수정상 처리 건수에 비슷한 수준이라면, 이건 애초에 다른 문제가 있는 것이다

    • 방어로직(배치 건 뭐건)은 일반적으로 자주 발생하지 않아야한다

      • 자주 발생하면 그건 우리 구현 문제거나 (이러면 내부에서 고쳐야하고), 외부 시스템의 문제라서 외부 협의를 통해서라도 고쳐야한다

  • 고객의 불편/불만/불안 최소화 할 수 있는 수준이어야한다

    • 예시] 서비스 사용 중 최대0.1%의 유저만 간헐적으로 해당 문제를 겪어야하며, 10분 이내에 자동 복구 or 취소 처리 or 기타 처리가 될 수 있어야한다

  • 97% 케이스를 24시간 동안 사람이 대응하지 않아야한다


모쪼록 답이 되었길 바라며 완강까지 화이팅 입니다!
감사합니다!

위고잉업님의 프로필 이미지
위고잉업
질문자

헉. 실무적인 답변 감사합니다!

사용하는 외부 API에서 정합성을 잘 제공하지 않는 경우라면 별도로 요청하는 그런 방법도 있군요!

또한 방어로직을 작성하는 것도 웬만한 상황에선 옳다는 확신이 들게 되었습니다.

감사합니다!

위고잉업님의 프로필 이미지
위고잉업

작성한 질문수

질문하기