532. 3PC (Three-Phase Commit) 비블로킹 프로토콜

⚠️ 이 문서는 중앙 통제자(코디네이터)가 죽었을 때 참가자들이 자물쇠를 쥔 채 영원히 얼어붙는 2PC의 치명적인 블로킹(Blocking) 문제를 해결하기 위해, **본격적인 커밋을 하기 전에 '예비 커밋(Pre-Commit)'이라는 단계를 하나 더 끼워 넣어 참가자들끼리 눈치껏 상황을 파악하고 락을 풀 수 있게 만든 '3PC'**를 다룹니다.

핵심 인사이트 (3줄 요약)

  1. 본질: 기존 2단계 커밋(2PC) 사이에 Pre-Commit 단계를 하나 더 추가하여, 총 3단계(CanCommit $\rightarrow$ PreCommit $\rightarrow$ DoCommit)로 분산 트랜잭션을 처리하는 알고리즘이다.
  2. 가치 (Non-Blocking): 코디네이터가 중간에 죽어버려도, 참가자들이 현재 자신이 어느 단계에 있는지 서로 확인하여 독자적으로 COMMIT을 할지 ROLLBACK을 할지 결정할 수 있게 해준다.
  3. 한계: 이론적으로는 데드락(블로킹)을 막아주지만, 네트워크를 세 번이나 왕복해야 하므로 끔찍하게 느리고 네트워크 단절 상황(Partition)에서는 여전히 데이터가 꼬일 위험이 있어 실무에서는 거의 쓰이지 않는다.

Ⅰ. 개요: 2PC의 구멍 메우기 (Context & Necessity)

2PC(531번 문서)에서 코디네이터가 PREPARE(준비해!) 명령을 내리고 기절해 버리면, 참가자들은 대답만 해놓고 무한 대기(Blocking)에 빠졌다. "아... 코디네이터가 1초 뒤에 COMMIT이라고 말하려고 했을까, 아니면 누군가 반대해서 ROLLBACK이라고 말하려고 했을까? 알 수가 없네."

이 모호함을 없애기 위해 3PC는 **Pre-Commit (예비 커밋)**이라는 중간 다리를 놓았다.

  • 코디네이터: "모두 COMMIT하기로 만장일치 됐어! 자, 다들 **예비 커밋 상태(Pre-Commit)**로 넘어가고 스탠바이해!"
  • 참가자들은 아직 진짜 도장을 찍진 않았지만, "아! 모두가 찬성했구나!"라는 전체 상황을 알게 된다.

이제 코디네이터가 기절해도 참가자들은 당황하지 않는다. "방금 나한테 예비 커밋하라고 했잖아? 그럼 무조건 만장일치가 나왔었다는 뜻이니까, 쟤 깨어날 때까지 기다리지 말고 그냥 우리끼리 COMMIT 치고 끝내버리자!" (블로킹 탈출 성공!)

📢 섹션 요약 비유: 2PC가 "하나, 둘..." 하고 바로 쏴버려서 심판이 기절하면 참가자가 당황하는 방식이라면, 3PC는 "하나, 둘, 반쯤 쏠 준비(Pre-Commit)... 셋!" 하고 중간에 신호를 하나 더 주는 것입니다. 만약 심판이 "반쯤 쏠 준비!"까지 외치고 기절했다면, 선수들은 "어차피 쏠 거였네" 하고 그냥 눈치껏 쏴버리는 것이죠.


Ⅱ. 3PC의 작동 3단계 ★

코디네이터가 죽었을 때를 대비한 타임아웃(Timeout) 규칙에 집중해야 한다.

1단계: CanCommit (할 수 있어?)

  • 코디네이터가 "너희들 트랜잭션 할 수 있어?"라고 묻는다.
  • 참가자들은 할 수 있으면 Yes, 못하면 No라고 대답한다.
  • 🚨 코디네이터 죽음: 아직 아무도 자물쇠(Lock)를 안 걸었기 때문에 그냥 **취소(Abort)**하면 된다.

2단계: PreCommit (예비 커밋)

  • 1단계에서 전원 Yes가 나왔다면, 코디네이터가 "모두 동의했으니 PreCommit 상태로 넘어가!"라고 명령한다.
  • 참가자들은 이 명령을 받고 나서야 진짜로 디스크에 데이터를 임시로 쓰고(Redo Log), 자물쇠를 꽉 쥔다.
  • 🚨 코디네이터 죽음:
    • 코디네이터가 타임아웃 되어서 대답이 없다.
    • 하지만 참가자들은 이미 "모두 동의했다"는 의미인 PreCommit 명령을 받은 상태다.
    • 따라서 코디네이터를 무시하고 독자적으로 다음 단계(Commit)로 그냥 넘어가 버린다. (블로킹 해결!)

3단계: DoCommit (진짜 커밋)

  • 코디네이터가 마지막으로 "진짜로 COMMIT 쳐!"라고 확인 사살을 한다.
  • 참가자들은 자물쇠를 풀고 트랜잭션을 끝낸다.

Ⅲ. 3PC의 치명적 단점: 뇌사 상태의 네트워크

"와! 블로킹이 해결됐네요? 그럼 무조건 3PC를 써야겠네요!" 하지만 3PC는 현실 세계의 '네트워크 파티션(네트워크 단절)'이라는 물리적 한계 앞에서 무참히 박살 난다.

  • 상황: 한국 서버(A)와 미국 서버(B)가 2단계(PreCommit)를 성공적으로 받았다.
  • 재앙 발생: 갑자기 태평양 해저 케이블이 끊어졌다. (네트워크 단절)
  • 코디네이터(C)는 A와 통신이 되지만, B와는 끊어졌다.
  • 코디네이터는 통신이 끊겼으므로 트랜잭션을 취소(ROLLBACK)하려고 A에게 취소 명령을 내렸다.
  • 하지만 B는 통신이 끊겼다(타임아웃). B는 3PC 규칙에 따라 "어? 아까 2단계 통과했으니까 무조건 성공이겠지?"라고 혼자 착각하고 독자적으로 COMMIT을 쳐버린다.
  • 최종 결과: A는 롤백, B는 커밋. 분산 데이터베이스의 데이터가 완벽하게 두 동강이 나버렸다.
┌──────────────────────────────────────────────────────────────┐
│           2PC와 3PC의 코디네이터 다운 시 블로킹/논블로킹 차이 시각화        │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ [ 🛑 2PC 상황 ]                                                │
│  코디네이터: "PREPARE 해!"                                       │
│  참가자 A, B: "준비됐어!"                                        │
│  코디네이터: (죽음 💥)                                            │
│  참가자 A, B: "... (뭐지? 남들이 찬성했나? 반대했나?) 무한 대기 ⏳"         │
│                                                              │
│ [ 🟢 3PC 상황 ]                                                │
│  코디네이터: "CanCommit 해?"                                     │
│  참가자 A, B: "응!"                                             │
│  코디네이터: "그럼 전원 만장일치니까 PreCommit 해!"                   │
│  참가자 A, B: "오케이!"                                          │
│  코디네이터: (죽음 💥)                                            │
│  참가자 A, B: "... (타임아웃) 아까 전원 만장일치라고 했으니까 그냥 COMMIT 하자!" │
└──────────────────────────────────────────────────────────────┘

Ⅳ. 결론

"너무 복잡한 동기화는 결국 또 다른 장애를 낳는다." 3PC는 2PC의 블로킹 문제를 학술적으로 해결하려던 우아한 논문 속의 알고리즘이다. 하지만 네트워크 왕복(Round-trip)이 3번이나 발생하여 속도가 끔찍하게 느려지는 데다가, 결정적으로 네트워크가 단절되는(Network Partition) 클라우드 환경에서는 데이터를 두 동강 내버리는 멍청한 오작동을 일으킨다. 결국 업계는 3PC를 폐기 처분했고, 무거운 동기화 프로토콜(2PC, 3PC) 대신에 비동기 메시지(Kafka)를 통해 실패 시 보상 트랜잭션을 던지는 '사가 패턴(Saga Pattern - 534번 문서)'으로 분산 트랜잭션의 패러다임을 완전히 전환하게 되었다.


📌 관련 개념 맵

  • 선행 기술: 2PC (Two-Phase Commit - 531번 문서)
  • 대체 기술: Saga Pattern (534번 문서)
  • 네트워크 문제: Network Partition (네트워크 단절 현상), CAP 이론 (463번 문서)
  • 특징: Non-blocking (비블로킹) 프로토콜

👶 어린이를 위한 3줄 비유 설명

  1. 2PC는 "하나, 둘, 출발!"이라고 외치는 거예요. 근데 반장이 "둘!" 하고 쓰러지면, 애들은 "출발하라는 거야, 말라는 거야?" 하고 계속 서 있죠.
  2. 3PC는 "하나, 둘, 셋, 출발!"로 한 단계를 더 넣었어요. "셋!"은 "이제 무조건 출발할 거야. 준비해!"라는 뜻이죠.
  3. 만약 반장이 "셋!"까지 외치고 쓰러지면, 애들은 "어차피 '셋'까지 불렀으니까 무조건 출발이겠네!" 하고 반장이 없어도 알아서 뛰어간답니다!