Appearance
영상 : https://www.youtube.com/watch?v=xpwRTu47fqY
양방향 무료 환전! MSA 환경에서 서로 데이터베이스도 다르게 보고 있을 때 트랜잭션을 어떻게 지켜내야할까?
분산 트랜잭션
2PC
- Commit 가능 여부를 질의 (Voting)
- DB가 가능하다고 응답
- 한 개라고 불가능하다고 응답한다면 이전 작업들을 모두 롤백한다.
강한 일관성, 낮은 가용성, 낮은 확장성
사가 패턴
각 서비스의 작은 트랜잭션들을 실행하면서 진행
특정 단계에서 실패하면 보상 트랜잭션 실행
높은 가용성, 높은 확장성, 중간 상태가 노출되고 보상 트랜잭션 구현을 필요로 한다.
- 코레오그래피 사가
- 중앙제어자 없이 메세지 브로커를 통해 이벤트를 교환하는 방식
- 단일장애지점이 없고 각 서비스가 느슨하게 결합됨
- 하지만 현재 진행중인 트랜잭션의 상태를 추적하거나 디버깅하기 어렵다.
- 오케스트레이션 사가
- 중간제어자가 직접 서비스에게 트랜잭션과 보상 트랜잭션을 명령하는 방식
- 중간제어자가 단일장애지점이 되고 모든 서비스들이 결합된다.
- 하지만 현재 진행중인 상태를 추적하기가 쉽다.
예외 핸들링
- 정상적인 실패
- 잔액 부족, 계좌해지, 거래제한
- 비정상적인 실패
- 서버에러, 타임아웃
사가패턴에서는 중간 상태가 노출되기 때문에 출금부터 진행해야 한다.
입금,출금은 HTTP로 동기처리로 진행하기 때문에 타임아웃 구현이 필요하다.
만약 출금은 성공했지만 입금에 실패한 경우 출금 취소로 처리한다.
상대 계좌 서버나 네트워크 문제로 출금 결과 확인에 실패한다면 어떻게 처리해야 하나?
카프카 메세지를 지연 발송하여 상대 계좌 서버나 네트워크 문제가 회복되는 시간을 벌 수 있다. (30초 → 1분 ..)
배치 재처리
환전 지연 이벤트를 발행하지도 못하고 서버가 죽은 경우 배치를 통해 ‘출금 취소’ → ‘환전 실패’ 처리
결과적 일관성
출금 취소에 실패한다면 CDL에 적재하여 지정한 횟수만큼 재시도 한다. 그래도 실패한다면 개발자가 직접 개입하여 DL 서버를 통해 다시 메시지를 발행한다.
DB : State Path
이벤트 조율을 오케스트레이터로 관리하기 때문에 매 상태를 확인하여 중간에 멈춘 환전을 알림으로 보낸다.
트랜잭셔널 메세징
입금 실패로 인한 환전 실패 처리와 출금 취소 메세지 발행은 항상 같이 이루어져야 한다!
즉, 로컬 트랜잭션 커밋과 메세지 발행이 원자적으로 이루어져야 한다.
트랜잭셔널 아웃박스 패턴으로 해결할 수 있지만, 토스는 프로듀서 데드 레터(PDL)로 해결한다.
출금취소 메시지 발행에 실패한다면 PDL에 메시지를 발행한다. DL서버가 PDL을 컨슘하여 브로커로 다시 메세지를 발행한다.
- 트랜잭셔널 아웃박스 패턴과 PDL에 대한 질문 Q. 내부적으로 메시징 발행 재처리가 DL 중심으로 잡혀 있는지? A. 예상하신대로 토스뱅크는 모든 토픽에 대하여 기본적으로 PDL이 적용되어 있습니다. 따라서 추가적인 아웃박스 패턴 등을 적용하지 않았습니다. Q. DL 서버에서 메시지 발행에 실패하면 어떻게 되는지? A. DL 서버의 PDL 메시지 처리도 컨슈머로 동작하므로, 발표에서 설명드린 CDL을 이용하여 재처리할 수 있습니다. Q. PDL이 아웃박스 패턴보다 나은 점 A. PDL/CDL은 플랫폼 팀에서 제공하고 있어 서비스 개발자 입장에서 느끼는 장점을 말씀드려 보자면, 모든 서비스에서 일괄 적용하기 쉽다는 장점이 있습니다. 아웃박스 패턴은 서비스 변경과 아웃박스 데이터 저장을 트랜잭션으로 묶어 처리해야 하므로, 서비스 DB 내에 아웃박스 테이블이 존재해야합니다. 토스뱅크에서는 수백개의 MSA 서버가 독립된 스키마(db)를 바라보고 있고, 이 스키마들은 수십개의 분리된 물리 서버 위에 그룹핑되어 존재합니다. 또, 사용하는 DB 역시 Oracle, MySQL, Mongo 등으로 다양합니다. 따라서 모든 MSA에 일괄적으로 아웃박스 패턴을 적용하려면, DB종류, 물리서버, 스키마마다 아웃박스 테이블들을 만들어줘야하고, 테이블에서 메시지를 발행하는 어플리케이션도 각각 작성해야 합니다. 반면 PDL은 모든 서버에서 동일한 메시지 브로커를 바라볼 수 있기 때문에, 라이브러리 형태로 제공되어 일괄 적용하는데 편리한 점이 있습니다. Q. PDL 메시지 브로커도 고가용성이 보장되는지, 그렇다면 불필요한 인프라 비용이 생기는 것은 아닌지? A. PDL 메시지 브로커로 서버에서 로그를 남길때 사용하는 로그 Kafka 클러스터를 사용하고 있습니다. 즉 고가용성을 위한 세팅이 적용되어 있으며 평상시에도 항상 사용하고 있기 때문에, PDL 메시지가 발행되지 않더라도 메시지 브로커에 문제가 생기면 그 즉시 알게 됩니다.
생각할 점
- 데이터 일관성을 아웃박스 패턴으로 해결할 수 있지만, 이 방법의 단점을 이해하고 PDL을 고려할 수 있음