참고자료
- Chris Richardson Microservices Pattern: Pattern: Saga
알렉스 쉬, Alex Xu 가상 면접 사례로 배우는 대규모 시스템 설계 기초 2 : 알라딘
우리가 은행/증권 앱에서 자주 사용하는 송금 기능은 트랜잭션의 원자성을 철저히 보장해야만 한다. TPS 가 높지 않은 서비스라면 송금과 관련된 쓰기 쿼리들은 단일 primary DB 노드에서 하나의 트랜잭션으로 묶어서 commit/rollback 하면 된다. 하지만 데이터베이스를 샤딩으로 나눌 만큼 TPS가 높은 서비스에서 사용자들의 계좌 정보가 서로 다른 샤드에 저장되어 있다면, 송금 트랜잭션의 원자성을 어떻게 보장할 수 있을까?
2PC(Two Phase Commit) 코디네이터를 별도로 둬서 코디네이터가 각 샤드 내 트랜잭션의 commit/rollback 을 조정하는 방법도 있으나 아래와 같은 단점이 있다.
- 2PC 코디네이터가 SPoF(Single Point of Failure)가 될 수 있다. SPoF 되지 않으려면 고가용성을 보장하도록 분산처리 되어야 하는데 구현 난이도가 너무 높다.
- 하나의 샤드에서 트랜잭션에 대한 결과를 코디네이터에게 전달할 때까지 다른 샤드의 트랜잭션이 대기해야 한다. 이는 데이터베이스 성능을 떨어트린다.
Saga
Saga 는 2PC 와 같이 분산된 노드를 대상으로 단일 트랜잭션을 수행하는 데 필요한 해결법 중 하나로 MSA 에서 표준으로 채택된 방법이다. Saga 는 크게 2가지 단계로 나뉜다.
- 각 샤드 내에서 수행할 연산을 순서대로 수행한다.
- 연산이 실패하면 전체 프로세스는 실패한 연산부터 맨 앞 연산까지 역순으로 보상 트랜잭션(compensating transaction) 을 통해 롤백한다.
예) 1번 샤드에서 사용자 A
계좌 감액 → 2번 샤드에서 사용자 B
계좌 증액
보상 트랜잭션 내에 있는 연산을 포함한 모든 연산들을 각 샤드에서 수행하도록 조율하는 방식은 2가지가 있다.
choreography
saga 트랜잭션에 관여하는 모든 서비스가 다른 서비스의 이벤트를 구독하여 작업하는 탈중앙화 방식으로, 이벤트 스트리머가 필요하다.
1. A 계좌 -1000 commit
- 데이터베이스에
A
계좌 출금과 관련된 트랜잭션 수행 ex) 잔액 갱신, 송금이력 생성 - 출금 트랜잭션에는 출금 이벤트가 성공적으로 발행되는 것까지 포함되어야 함
2. A 계좌 출금 이벤트 발행
- A 계좌에서 출금했음을 알리는 이벤트 발행
- 이벤트 페이로드 예시
transfer_id
키/값은 이벤트를 수신하는 곳에서 멱등성을 보장하기 위한 수단
{
"state": "DEBIT_SUCCEED"
"fromAccount": "A",
"toAccount": "B",
"amount": 1000,
"transfer_id": "78453453",
}
3. A 계좌 출금 이벤트 수신
- A 계좌에서 출금했음을 알리는 이벤트 수신
4. B 계좌 +1000 commit
- 데이터베이스에
B
계좌 증액과 관련된 트랜잭션 수행 ex) 잔액 갱신, 입금이력 생성
.png&w=3840&q=90)
4. B 계좌 +1000 rollback
- 모종의 이유로 데이터베이스에서 롤백 발생 ex) 계좌 유효성 검사 실패, 샤드 다운 이슈
5. B 계좌 입금실패 이벤트 발행
- B 계좌에 입금 처리가 되지못했음을 알리는 이벤트 발행
- 이벤트 페이로드 예시
{
"state": "CREDIT_FAILED",
"fromAccount": "A",
"toAccount": "B",
"amount": 1000,
"reason": ...,
"transfer_id": "78453454",
}
6. 계좌 입금실패 이벤트 수신
- B 계좌 입금에 실패했음을 알리는 이벤트 수신
7. 계좌 + 1000 commit
- B 계좌 입금에 실패했으므로 A 계좌 출금에 대한 보상 트랜잭션 수행 ex) 잔액 갱신, 출금이력 삭제
orchestration
하나의 코디네이터가 모든 서비스들이 순서대로 작업을 실행하도록 조율하는 중앙화 방식
(작성중)
- 송금 서비스에서 saga 가 활용되는 사례 (다이어그램)
- 연산 순서의 2가지 방식 (코레오그래피, 오케스트레이션)
- 샤드 대상으로 saga 구현한 예시 코드
- MSA 에서 saga 가 사용되는 사례 (다이어그램)