Q.여러 서비스에 걸친 트랜잭션을 어떻게 처리하시겠어요?
하나의 트랜잭션으로 묶지 않고, 각자 커밋하고 실패하면 보상하는 쪽으로 갑니다.
| 방식 | 내용 | 실무 |
|---|
| 2단계 커밋 | 조정자가 전부 준비 확인 후 커밋 | 거의 안 쓴다. 조정자 장애 시 멈춘다 |
| 사가 | 단계별로 커밋하고 실패 시 역순 보상 | 주로 이 방식 |
| 이벤트 기반 결과적 일관성 | 이벤트로 전파해 각자 맞춘다 | 흔하다 |
| 경계 재설계 | 함께 바뀌어야 하는 것을 한 서비스로 | 가능하면 이것이 최선 |
마지막을 먼저 검토해야 합니다. 분산 트랜잭션이 필요하다는 것은 서비스 경계가 잘못 그려졌다는 신호인 경우가 많습니다. 항상 함께 바뀌는 데이터라면 한 서비스 안에 있어야 합니다.
사가에서 정할 것들입니다.
| 항목 | 내용 |
|---|
| 보상 동작 | 취소가 아니라 되돌리는 별도 행동. 환불, 재고 복원 |
| 중간 상태 노출 | 사용자에게 "처리 중"을 어떻게 보일지 |
| 멱등성 | 각 단계와 보상이 여러 번 실행돼도 안전해야 한다 |
| 보상 실패 | 보상도 실패할 수 있다. 그때는 사람이 개입한다 |
흔한 실수: 보상을 롤백과 같게 보는 것. 이미 커밋됐으므로 되돌릴 수 없고, 반대 방향의 새 작업을 해야 합니다. 이메일을 보냈다면 취소 메일을 보내는 식입니다.
Q.2PC를 실무에서 잘 쓰지 않는 이유는 무엇인가요?
| 이유 | 내용 |
|---|
| 조정자가 단일 장애점 | 커밋 결정 직전에 죽으면 참여자가 잠금을 쥔 채 멈춘다 |
| 잠금 유지 시간 | 전체 합의가 끝날 때까지 자원을 잠근다 |
| 가용성 저하 | 참여자 하나가 응답하지 않으면 전체가 진행되지 않는다 |
| 지원 범위 | 외부 API 나 메시지 큐는 참여할 수 없다 |
| 규모 | 참여자가 늘면 실패 확률과 지연이 함께 는다 |
첫 번째가 결정적입니다. 참여자는 준비 응답을 보낸 뒤 커밋도 취소도 못 하고 기다립니다. 조정자가 복구될 때까지 그 데이터는 잠겨 있습니다.
네 번째도 현실적인 제약입니다. 마이크로서비스 환경에서 트랜잭션에 참여하는 대상은 대개 다른 서비스의 HTTP API 이고, 그것은 2단계 커밋 규약을 지원하지 않습니다.
그래도 쓰는 곳이 있습니다. 같은 조직이 관리하는 소수의 DB 사이, 지연에 여유가 있는 배치 작업 정도입니다.
흔한 실수: 2단계 커밋이 정합성을 완전히 보장한다고 답하는 것. 조정자와 참여자가 동시에 죽는 경우 등 남는 구멍이 있고, 그것을 메우려면 합의 알고리즘까지 필요합니다.
Q.코레오그래피와 오케스트레이션 중 무엇을 고르시겠어요?
| 항목 | 코레오그래피 | 오케스트레이션 |
|---|
| 흐름 지식 | 각 서비스가 자기 다음만 안다 | 조정자가 전체를 안다 |
| 결합도 | 낮다 | 조정자가 모두를 안다 |
| 흐름 파악 | 코드가 흩어져 있어 어렵다 | 한곳에 모여 있다 |
| 디버깅 | 어렵다. 트레이싱이 필수 | 상태를 조회할 수 있다 |
| 단계 추가 | 관련 서비스만 고친다 | 조정자를 고친다 |
| 맞는 규모 | 단계가 적고 단순할 때 | 단계가 많고 분기가 있을 때 |
단계가 3개를 넘고 보상이 필요하면 오케스트레이션이 낫습니다. 결제, 재고, 배송이 이벤트로 얽히면 지금 어디까지 진행됐는지 아는 곳이 없어서 장애 대응이 어렵습니다.
반대로 단계가 둘이고 보상이 필요 없으면 코레오그래피가 가볍습니다. 주문 생성 후 알림 발송 정도라면 조정자를 둘 이유가 없습니다.
흔한 실수: 결합도가 낮다는 이유로 코레오그래피를 고르는 것. 낮아지는 것은 코드 결합이고, 흐름에 대한 이해는 오히려 흩어져 운영이 어려워집니다. 상태를 물어볼 곳이 있는지가 실무에서 더 중요합니다.
Q.DB 저장과 이벤트 발행이 함께 성공하도록 어떻게 보장하나요?
두 시스템에 각각 쓰는 것은 원자적이지 않습니다. DB 트랜잭션 안에 이벤트도 함께 저장하는 방식으로 해결합니다.
| 순서 | 동작 |
|---|
| 1 | 업무 데이터와 이벤트를 같은 트랜잭션으로 저장한다 |
| 2 | 커밋된다. 둘 다 저장되거나 둘 다 안 된다 |
| 3 | 별도 프로세스가 저장된 이벤트를 읽어 발행한다 |
| 4 | 발행에 성공하면 표시한다 |
이것이 흔히 아웃박스 패턴이라 부르는 구조입니다. 발행이 실패하면 다시 시도하면 되고, 중복 발행될 수 있으니 소비자를 멱등하게 만듭니다.
대안도 있습니다.
| 방식 | 내용 |
|---|
| 변경 로그 구독 | DB 의 변경 로그를 읽어 이벤트로 만든다. 코드 변경이 적다 |
| 이벤트를 원본으로 | 이벤트를 먼저 저장하고 상태를 그것으로 만든다 |
흔한 실수: 커밋 후에 발행하는 것으로 충분하다고 보는 것. 커밋과 발행 사이에 프로세스가 죽으면 데이터는 있고 이벤트는 없습니다. 반대로 먼저 발행하면 롤백된 일에 대한 이벤트가 나갑니다. 어느 순서로도 두 시스템을 원자적으로 묶을 수 없습니다.
먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.
읽었으면 문제로 확인해보세요
분산 시스템 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.