여러 노드의 트랜잭션을 하나로 묶어 전부 커밋하거나 전부 롤백하는 프로토콜 (Two-Phase Commit, 2단계 커밋).
두 단계
다이어그램 로딩 중…
1단계에서 한 명이라도 "아니오"라고 하면 전원에게 롤백을 지시한다.
핵심 — 준비 단계의 의미
참여자가 "예"라고 답하는 것은 "나는 반드시 커밋할 수 있다"는 약속이다. 이후 코디네이터가 커밋을 지시하면 거절할 수 없다.
그래서 참여자는 "예"를 보내기 전에 로그를 디스크에 기록하고 락을 유지한다. 자기가 재시작되더라도 약속을 지킬 수 있어야 하기 때문이다.
치명적 약점 ① — 코디네이터 단일 장애점
참여자들이 "예"라고 답한 직후 코디네이터가 죽으면?
참여자들은 커밋인지 롤백인지 모른 채
- 락을 쥐고 무한 대기한다 — ← blocking protocol
참여자끼리 상의해도 답이 안 나온다. 자기는 "예"였지만 남이 "아니오"였는지 알 수 없다. 코디네이터가 살아날 때까지 그 데이터를 아무도 못 건드린다.
치명적 약점 ② — 성능
락을 쥔 시간 = 1단계 + 네트워크 왕복 + 2단계
- = 가장 느린 참여자에 맞춰진다
참여자가 많고 지연이 크면 락 유지 시간이 길어져 동시성이 급락한다.
3PC는 왜 안 쓰나
준비 단계를 하나 더 넣어 블로킹을 줄이려는 시도지만, 네트워크 분단 상황에서는 여전히 틀린 결정을 내릴 수 있고 단계가 늘어 더 느리다. 실무에서 거의 안 쓴다.
그래서 MSA는 2PC를 피한다
XA 트랜잭션(2PC 표준)의 문제
- 서비스 간 결합도가 극도로 높아진다
- 한 서비스가 느리면 전체가 느려진다
- Kafka·대부분의 NoSQL·외부 API는 XA를 지원하지 않는다
- 클라우드 환경에서 인스턴스는 언제든 사라진다
대안 — Saga 패턴. 원자성을 포기하고 보상 트랜잭션으로 되돌린다. 최종 일관성을 받아들이는 대신 결합도와 락을 없앤다.
그래도 2PC가 살아 있는 곳
- 단일 DB 내부 — InnoDB는 redo 로그와 binlog 사이에 내부적으로 2PC를 쓴다
(그래서
sync_binlog=1이 느리다) - Kafka의 트랜잭션 — 오프셋 커밋과 메시지 발행을 원자적으로 묶을 때
- 레거시 엔터프라이즈 시스템(금융권 XA)
"통제된 경계 안에서는 유효하지만, 서비스 경계를 넘어가면 부적합하다" 가 정리다.