3PC: PreCommit 단계로 보는 분산 트랜잭션 커밋

3PC의 CanCommit·PreCommit·DoCommit 흐름과 2PC 블로킹 문제, 장애 처리 방식 및 분산 트랜잭션 설계 고려사항을 정리한다.

2026-08-14 · 최초 발행 2025-08-10

2PC가 멈추는 지점에 PreCommit을 둔다

3PC(Three-Phase Commit)는 분산 데이터베이스에서 트랜잭션의 원자성과 일관성을 유지하기 위한 커밋 프로토콜이다. 출발점은 2PC(Two-Phase Commit)의 블로킹 문제다. 코디네이터가 장애를 일으켰을 때 참가자가 무기한 대기하는 상황을 줄이고, 코디네이터가 없어도 다음 결정을 내릴 수 있는 여지를 만드는 데 목적이 있다.

핵심은 커밋 여부를 묻고 바로 최종 반영으로 넘어가지 않는다는 점이다. 3PC는 중간의 PreCommit 상태를 두고, 단계별 타임아웃 시 어떤 행동을 할지 정한다.

2PC의 대기 상태와 3PC의 차이

2PC에서는 코디네이터가 준비 완료 응답을 받은 뒤 커밋 지시를 내린다.

코디네이터참가자2참가자1코디네이터참가자2참가자1준비 완료준비 완료커밋 지시커밋 지시커밋 완료커밋 완료

이 구조에서는 코디네이터가 단일 장애점이 된다. 장애 시 참가자가 언제 중단하거나 커밋해야 하는지 판단하기 어렵고, 타임아웃이 발생했을 때도 결정이 모호하다.

3PC는 PreCommit 단계를 추가해 이 경계를 나눈다. 모든 단계에 타임아웃 규칙을 두고, 코디네이터 실패 이후에도 복구 절차를 진행할 수 있도록 설계한다.

CanCommit에서 실행 가능 여부를 먼저 확인한다

첫 단계인 CanCommit은 트랜잭션을 수행할 수 있는지 확인하는 구간이다. 코디네이터는 모든 참가자에게 수행 가능 여부를 묻고, 참가자는 리소스를 잠그지 않은 채 Yes 또는 No로 응답한다.

모든 응답이 Yes이면 다음 단계로 넘어간다. 하나라도 No이면 트랜잭션을 중단하고 모든 참가자에게 Abort 메시지를 보낸다.

참가자2참가자1코디네이터참가자2참가자1코디네이터CanCommit?CanCommit?YesYes

PreCommit은 작업 결과를 준비 상태에 고정한다

CanCommit에서 모든 참가자가 Yes를 반환하면 코디네이터는 PreCommit 메시지를 전송한다. 그렇지 않으면 Abort를 보낸다.

PreCommit을 받은 참가자는 트랜잭션 작업을 실행하고 로그를 기록한 뒤, 커밋 가능한 상태가 되었음을 ACK로 알린다. Abort를 받았다면 트랜잭션을 중단하고 ACK를 반환한다.

참가자2참가자1코디네이터참가자2참가자1코디네이터PreCommitPreCommitACKACK

이 준비 상태가 3PC의 핵심이다. 최종 커밋 전의 상태를 명확히 구분함으로써, 장애 이후 참가자와 새 코디네이터가 처리 방향을 판단할 수 있다.

DoCommit에서 최종 반영 또는 롤백을 수행한다

모든 PreCommit ACK를 받으면 코디네이터는 DoCommit을 전송한다. 타임아웃이나 실패가 발생하면 Abort를 전송한다.

DoCommit을 수신한 참가자는 최종 커밋을 수행하고 리소스 잠금을 해제한 뒤 ACK를 돌려준다. Abort를 받으면 롤백과 잠금 해제를 수행하고 ACK를 반환한다.

참가자2참가자1코디네이터참가자2참가자1코디네이터DoCommitDoCommitACKACK

장애 상황에서의 판단 기준

코디네이터가 CanCommit 단계에서 실패하면 참가자는 타임아웃 뒤 트랜잭션을 중단한다. PreCommit 단계에서 실패했을 때는 PreCommit 메시지를 받은 참가자가 존재하면 새 코디네이터를 선출해 커밋을 진행하며, 메시지를 받지 못한 참가자는 타임아웃 뒤 중단한다. DoCommit 단계의 장애에서는 모든 참가자가 PreCommit 상태이므로 새 코디네이터를 선출해 커밋을 진행한다.

참가자가 응답하지 않으면 코디네이터는 타임아웃 뒤 해당 참가자를 제외하고 진행할 수 있다. 부분 장애가 발생해도 나머지 참가자와 트랜잭션을 계속 진행하며, 장애 참가자는 복구 후 로그를 확인해 일관성을 유지할 수 있다.

네트워크 분할이 생기면 각 파티션에서 새 코디네이터를 선출할 수 있다. CanCommit과 PreCommit 사이에서 타임아웃이 발생하면 중단하고, PreCommit 이후의 타임아웃에서는 커밋을 진행한다. 모든 파티션이 같은 타임아웃 규칙을 적용하는 것이 일관성 유지의 전제가 된다.

가용성과 복잡성의 교환

3PC는 2PC보다 한 단계가 더 있으므로 메시지 수가 늘고, 트랜잭션 완료 시간도 길어진다. 참가자의 상태 정보를 유지하기 위한 추가 메모리도 필요하다.

한편 네트워크 파티션이 발생하지 않는다는 가정이 필요하며, 시간 동기화가 정확하지 않은 경우 타임아웃 기반 결정이 일관성 문제로 이어질 수 있다. 특정 상황에서는 블로킹도 남아 있다. 2PC보다 구현이 복잡하고 테스트도 어렵다는 점을 설계 단계에서 감안해야 한다.

구현과 운영에서 확인할 항목

타임아웃은 네트워크 지연과 처리 시간을 고려해 설정해야 한다. 하트비트와 모니터링 시스템은 장애 감지에 쓰이고, 복구를 위해서는 로그 기록과 관리 방식이 필요하다.

메시지 오버헤드를 낮추려면 다수의 트랜잭션을 배치로 묶을 수 있다. 읽기 일관성 요구사항이 낮은 경우에는 비동기 커밋을 사용할 수 있으며, 물리적으로 가까운 노드 사이의 트랜잭션을 우선 처리하는 방식도 고려 대상이다.

운영 환경에서는 트랜잭션 상태와 성능을 모니터링하고, 장애 시 자동 복구 절차를 마련해야 한다. 트랜잭션 볼륨 증가를 고려한 확장성 설계도 함께 필요하다.

3PC를 대신하거나 확장하는 접근

일부 분산 PostgreSQL 구현은 3PC 변형을 사용하며, MongoDB 샤딩 환경에도 변형된 3PC 메커니즘이 적용된다. AWS DynamoDB는 트랜잭션 처리에 3PC 기반 프로토콜을 적용하고, Google Spanner는 TrueTime과 결합한 변형 커밋 프로토콜을 사용한다.

Paxos Commit은 3PC와 Paxos를 결합해 더 강한 일관성을 보장하는 방식이다. Raft 기반 커밋은 Raft 합의 알고리즘을 활용하며, Presumed Abort/Commit은 장애 상황의 기본 동작을 미리 정한 변형이다. Raft/Paxos를 커밋 프로토콜과 통합하거나 BFT(Byzantine Fault Tolerance) 기반 커밋 프로토콜을 사용하는 흐름도 있다.

즉시 일관성을 항상 요구하지 않는 경우에는 BASE 접근법, 보상 트랜잭션을 사용하는 SAGA 패턴, 최종 일관성 모델이 대안이 된다. 블록체인의 스마트 컨트랙트와 분산 원장 합의 메커니즘을 트랜잭션 보장에 활용하는 방식도 같은 맥락에서 검토할 수 있다.

3PC는 2PC의 블로킹 문제를 완화하기 위해 등장했지만 완전한 해결책은 아니다. 그럼에도 PreCommit 상태와 타임아웃 규칙은 분산 트랜잭션에서 장애 이후의 결정을 어떻게 설계할지 이해하는 기반이 된다.

분산 트랜잭션3PC2PC데이터베이스분산 시스템