2단계 커밋
여러 곳에 흩어진 데이터를 한꺼번에 커밋하거나 한꺼번에 취소하기 위한 규칙입니다. 한쪽이 조정자가 되어 나머지에게 먼저 준비가 됐는지 묻습니다. 전부 된다고 답해야 커밋을 통보하고, 하나라도 안 된다고 하면 전부 취소합니다.
쉽고 빠른 이해
2단계 커밋은 여러 곳에 나뉜 트랜잭션 하나를 한 덩어리로 커밋하거나 한 덩어리로 취소하게 맞추는 절차입니다. PostgreSQL 이나 MySQL 처럼 여러 데이터베이스가 한 트랜잭션에 걸릴 때 씁니다.
이게 없으면 한쪽은 커밋되고 다른 쪽은 실패해서, 데이터가 반쪽만 반영된 채로 남을 수 있습니다. 2단계 커밋은 이 반쪽짜리 상태 자체를 없앱니다.
돌아가는 방식은 이렇습니다.
- 조정자가 모든 참가자에게 준비가 됐는지 묻습니다
- 참가자 전원이 찬성해야 커밋을 통보합니다. 하나라도 취소를 내면 전원에게 취소를 통보합니다
- 참가자는 판정을 받을 때까지 자원과 잠금을 쥐고 기다립니다
대가는 대기 시간입니다. 조정자가 판정을 못 돌려주는 동안 참가자는 커밋도 취소도 못 하고 잠금을 쥔 채 멈춰 있습니다. 그래서 준비된 트랜잭션을 잊지 않고 정리해 줄 별도 프로그램을 세워 두지 않았다면, 이 기능 자체를 꺼 두는 편이 낫습니다.
상세
2단계 커밋은 트랜잭션 하나의 결말을 여러 참가자가 같은 값으로 확정하게 맞추는 합의 프로토콜입니다. 참가자는 서로 다른 노드에 놓인 별개의 프로세스일 수도 있고, 한 프로세스 안에서 독립적으로 도는 구성요소일 수도 있습니다. 마이크로소프트가 공개한 MS-DTCO(MSDTC Connection Manager: OleTx Transaction Protocol) 명세는 이것을 루트 응용(트랜잭션을 시작하고 커밋을 요청하는 응용 프로그램)의 커밋 요청에 대해 원자적 트랜잭션의 결말을 확정하는 합의 프로토콜이라고 정의합니다. 그리고 1단계와 2단계가 이 프로토콜의 서로 구별되는 두 국면이라고 못 박습니다. 같은 명세는 1단계를 준비 국면이라고도 부르며, 1단계가 끝나는 시점에 트랜잭션의 결말이 이미 정해져 있다고 적습니다.
두 역할
역할은 둘입니다. 지금까지 조정자·참가자라고 부른 이 두 역할을, MySQL 공식 문서는 여러 곳에 나뉜 트랜잭션 조각들을 하나로 묶어 부르는 전역 트랜잭션을 다룰 때 X/Open 의 분산 트랜잭션 처리 명세 XA 를 따라 이렇게 가릅니다.
| 역할 | 앞에서 쓴 이름 | 하는 일 |
|---|---|---|
| TM(Transaction Manager, 트랜잭션 관리자) | 조정자 | 전역 트랜잭션에 속한 트랜잭션들을 조정합니다. 각 트랜잭션을 다루는 자원 관리자들과 통신합니다 |
| RM(Resource Manager, 자원 관리자) | 참가자 | 트랜잭션 자원에 접근할 길을 제공합니다. 데이터베이스 서버가 자원 관리자의 한 종류입니다. 자기가 관리하는 트랜잭션을 커밋하거나 되돌릴 수 있어야 합니다 |
전역 트랜잭션 안의 개별 트랜잭션들을 MySQL 문서는 그 전역 트랜잭션의 브랜치라고 부릅니다. MS-DTCO 는 같은 두 역할을 트랜잭션 관리자와 자원 관리자로 부르고, 지정된 트랜잭션 하나에 대해 자원 관리자가 정확히 하나의 트랜잭션 관리자에 등록해 결말에 투표하고 최종 결말을 받아 간다고 적습니다. 커밋 요청과 시작 요청을 함께 처리하는 트랜잭션 관리자가 루트 트랜잭션 관리자이고, 한 트랜잭션에 루트는 정확히 하나입니다.
MS-DTCO 가 말하는 원자적 트랜잭션은 참여 자원 관리자 안에서 상태가 바뀔 때 ACID(Atomicity·Consistency·Isolation·Durability, 원자성·일관성·격리성·지속성) 성질을 이루기 위한 장치입니다. 2단계 커밋은 그중 원자성을 여러 자원 관리자에 걸쳐 세우는 자리입니다.
두 단계로 가른 이유
Jim Gray 는 1978년 글 「Notes on Data Base Operating Systems」에서 두 장군 문제(통신이 언제든 끊길 수 있는 상황에서 두 편이 같은 순간에 함께 움직이기로 확실히 합의할 방법이 없다는 문제)에는 해가 없다고 먼저 적습니다. 그리고 프로토콜의 길이(주고받는 메시지 수)에 유한한 상한을 두어야 한다는 제약을 풀면 해가 가능해진다고 이어 갑니다. 그 해가 커밋 조정자를 두는 것입니다. 조정자는 모든 참가자에게 통신 경로를 갖습니다.
조정자는 모든 참가자에게 무슨 일이 생기든 트랜잭션을 다시 하거나 되돌릴 수 있는 상태로 들어가라고 요청합니다. Gray 는 이것이 로그를 아주 안전한 곳에 적는다는 뜻이라고 풀어 적습니다. 그러고 나서 표를 걷습니다. 하나라도 취소를 냈으면 전원에게 취소를 알립니다. 전원이 찬성했으면 커밋 레코드를 로그에 동기로 적은 뒤 전원에게 커밋을 알립니다. Gray 는 이 방식이 서는 열쇠가 커밋 결정이 한 곳에 모여 있고 시간에 쫓기지 않는다는 점이라고 적습니다.
이름의 두 단계는 로그 레코드를 기준으로 갈립니다. Gray 는 커밋이 PHASE12_COMMIT 또는
AGREE_COMMIT 로그 레코드가 쓰이기 전과 후로 나뉘며, 그래서 2단계 커밋 프로토콜이라고
부른다고 적습니다. MySQL 공식 문서도 전역 트랜잭션을 실행하는 과정이 2PC(two-phase
commit, 2단계 커밋)를 쓴다고 적고, 이 과정이 브랜치들의 실제 작업이 끝난 뒤에 일어난다고
덧붙입니다.
교환 순서
정상 왕복 하나는 네 번의 메시지입니다. 조정자가 준비를 묻고, 참가자가 찬반을 답하고, 조정자가 결말을 통보하고, 참가자가 확인을 돌려줍니다.
sequenceDiagram
participant 조정자
participant 참가자
조정자->>참가자: REQUEST_COMMIT
Note over 참가자: undo(되돌리기)·redo(다시하기) 로그를 비휘발성 저장소로 강제로 내린다
alt 강제로 내리는 데 성공
참가자-->>조정자: AGREE
Note over 조정자: PHASE12_COMMIT 을 동기로 적는다
조정자->>참가자: COMMIT
참가자-->>조정자: ACKNOWLEDGE
else 실패
참가자-->>조정자: ABORT
end
1단계에서 조정자는 각 참가자에게 REQUEST_COMMIT 을 보냅니다. 참가자는 undo/redo 로그를
비휘발성 저장소로 강제로 내리고, 그것이 성공하면 AGREE 를, 실패하면 ABORT 를 답합니다.
Gray 의 참가자 의사코드는 AGREE 를 답하기 전에 로그에 찬성을 적는다고 적어 두었습니다.
2단계는 표를 다 걷은 뒤입니다. 하나라도 취소를 냈으면 조정자는 전원에게 ABORT 를
브로드캐스트하고 자기 로그에 취소를 적고 끝냅니다. 이때 각 참가자가 자기 표를 무엇으로
냈는지는 상관없습니다 — 자신은 AGREE 를 보낸 참가자도, 다른 참가자가 하나라도 ABORT 를
냈으면 똑같이 취소를 받습니다.
sequenceDiagram
participant 조정자
participant 참가자A
participant 참가자B
참가자A-->>조정자: AGREE
참가자B-->>조정자: ABORT
Note over 조정자: 자기 로그에 취소를 적는다
조정자->>참가자A: ABORT
조정자->>참가자B: ABORT
전원이 찬성했으면 조정자는 PHASE12_COMMIT 레코드를 로그에 동기로 적은 다음 전원에게
COMMIT 을 브로드캐스트하고, 참가자마다 확인 응답(ACKNOWLEDGE)을 받고 나서 끝냅니다. Gray 의 의사코드는
확인이 올 때까지 기다리다 시간 제한에 걸리면 다시 보내도록 적혀 있습니다. 취소를
브로드캐스트했을 때도 같은 자리에서 끝나는데, 이 마무리 지점에서 조정자는
COORDINATOR_COMPLETE 레코드를 로그에 적습니다. 참가자 쪽은 판정을 받고 움직입니다.
커밋이면 자원과 잠금을 놓고 확인을 돌려줍니다. 취소면 자기 작업을 되돌린 뒤 확인을
돌려줍니다.
참가자가 N 이면 커밋에 4N 개의 메시지가 듭니다. 조정자가 참가자마다 두 번 부르기 때문입니다 — 표를 걷느라 한 번, 결과를 알리느라 한 번인데, 부를 때마다 요청과 응답이 오가는 왕복이라 한 번의 호출이 메시지 두 개입니다. 이 4N 은 재전송이 없을 때의 수이고, 바로 위에서 다룬 시간 제한 재전송까지 치면 메시지 수는 이보다 늘어날 수 있습니다. Gray 는 호출과 반환이 비싼 경우 더 절약하는 프로토콜을 원할 수 있다고 적고, 중첩 2단계 커밋을 그런 최적화의 하나로 이어서 다룹니다.
MS-DTCO 의 메시지와 투표 값
실제 와이어 위에서 이 네 메시지가 어떤 이름을 갖는지는 명세마다 다릅니다. MS-DTCO 는 이렇게 적습니다.
| 방향 | 메시지 | 뜻 |
|---|---|---|
| 조정자 → 참가자 | TXUSER_ENLISTMENT_MTAG_PREPAREREQ |
커밋할 준비를 하는 데 필요한 동작을 수행하라는 요청 |
| 참가자 → 조정자 | TXUSER_ENLISTMENT_MTAG_PREPAREREQDONE |
준비 작업의 성공 또는 실패. 결과는 prepareReqDone 필드가 담습니다 |
| 조정자 → 참가자 | TXUSER_STATUS_MTAG_COMMITTED |
트랜잭션이 커밋됐다는 통지 |
| 조정자 → 참가자 | TXUSER_STATUS_MTAG_ABORTED |
트랜잭션이 취소됐다는 통지 |
명세는 단일 단계 커밋을 트랜잭션 관리자가 유일한 하위 참가자(그 트랜잭션 관리자
바로 아래 있는, 하나뿐인 참가자)에게 결말을 정할 권리를 넘기는 최적화로 정의합니다. 준비
요청에는 fSinglePhase 필드가 함께 실려 이 최적화를 쓸지를 정합니다. 값이 0 이면 이
메시지를 받은 자원 관리자는 단일 단계 커밋을 수행하면 안 됩니다. 0 이 아니면 수행할 것을
권합니다.
투표는 찬반 둘이 아니라 네 값입니다. TXUSER_ENLISTMENT_PREPAREREQDONE_OK 는 준비가
성공했고 이 등록이 트랜잭션 결말을 필요로 한다는 뜻입니다. ..._ABORT 는 준비가 실패했고
트랜잭션을 반드시 취소해야 한다는 뜻입니다. ..._READONLY 는 준비는 성공했지만 이 트랜잭션에
더 관여할 일이 없다는 뜻입니다. ..._SINGLEPHASE_COMMIT 은 보낸 쪽이 위 최적화를 골라
이미 커밋했다는 뜻입니다.
이 최적화는 In Doubt(루트 응용이 커밋을 요청했는데 트랜잭션 관리자가 실제 커밋·취소
결정을 확인하지 못한 상태) 결말을 낳을 수 있다고 명세는 적습니다. 결말을 지속 저장소에
적는 일을 취소 쪽에서 생략하는 추정 취소도 같은 자리에 최적화로 적혀 있습니다. 커밋
쪽만 로그에 남기는 이유는 커밋이 PHASE12_COMMIT 레코드가 쓰이기 전과 후로 갈리기
때문입니다 — 그 레코드가 없다는 사실 자체가 이미 취소를 뜻하므로, 취소는 따로 적어 둘
필요가 없습니다.
참가자의 상태
MySQL 의 XA 트랜잭션은 명령마다 상태가 옮겨 갑니다. XA START 를 내면 ACTIVE 상태로
들어가고 XA END 를 내면 IDLE 로 넘어가며, XA PREPARE 를 내면 PREPARED 상태로 남습니다.
stateDiagram-v2
[*] --> ACTIVE: XA START
ACTIVE --> IDLE: XA END
IDLE --> PREPARED: XA PREPARE
IDLE --> [*]: XA COMMIT ... ONE PHASE
PREPARED --> [*]: XA COMMIT
PREPARED --> [*]: XA ROLLBACK
PREPARED 상태에서 XA COMMIT 을 내면 커밋하고 트랜잭션을 끝내고, XA ROLLBACK 을 내면
되돌리고 끝냅니다. IDLE 상태에서는 XA PREPARE 대신 XA COMMIT ... ONE PHASE 를 낼 수도
있습니다. 이쪽은 준비와 커밋을 한 번에 끝내고 트랜잭션을 종료합니다. PREPARED 로 가지
않으므로 그 xid(트랜잭션을 가리키는 식별자)는 XA RECOVER 문이 보여주는 목록에도 나오지
않습니다.
예시
PostgreSQL
PostgreSQL 은 준비와 확정을 서로 다른 명령으로 갈라 둡니다. 준비는 트랜잭션 블록 안에서 칩니다. 확정은 그 반대로 트랜잭션 블록 밖에서 칩니다.
PREPARE TRANSACTION 'foobar';
COMMIT PREPARED 'foobar';
ROLLBACK PREPARED 'foobar';
'foobar' 는 나중에 이 트랜잭션을 가리킬 임의의 식별자입니다. 문자열 리터럴로 적어야 하고
200바이트 미만이어야 하며, 지금 준비 상태에 있는 어떤 트랜잭션의 식별자와도 겹치면 안 됩니다.
PREPARE TRANSACTION 을 치고 나면 그 트랜잭션은 현재 세션과 떨어져 나가고 상태가 전부
디스크에 저장됩니다. 확정 명령은 원래 트랜잭션을 실행한 세션이 아니어도, 어느 세션에서나
낼 수 있습니다. 다만 원래 실행한 사용자이거나 슈퍼유저여야 합니다. COMMIT PREPARED 와
ROLLBACK PREPARED 는 트랜잭션 블록 안에서 실행할 수 없습니다. 준비된 트랜잭션이 그 자리에서
바로 확정됩니다.
준비 상태로 남은 것은 시스템 뷰로 봅니다.
| 컬럼 | 타입 | 담는 것 |
|---|---|---|
transaction |
xid |
준비된 트랜잭션의 숫자 트랜잭션 식별자 |
gid |
text |
그 트랜잭션에 배정된 전역 트랜잭션 식별자 |
prepared |
timestamptz |
커밋을 위해 준비된 시각 |
owner |
name |
그 트랜잭션을 실행한 사용자 이름 |
database |
name |
그 트랜잭션이 실행된 데이터베이스 이름 |
pg_prepared_xacts 는 준비된 트랜잭션 하나당 한 행을 갖고, 커밋되거나 되돌려지면 그 행이
사라집니다. PostgreSQL 문서는 이 뷰를 읽는 동안 내부 트랜잭션 관리자 자료구조가 잠시 잠기고
복사본이 만들어진다고 적습니다.
MySQL
MySQL 은 InnoDB 스토리지 엔진에서 XA 트랜잭션을 지원합니다. 한 왕복이 명령으로 그대로 드러납니다.
mysql> XA START 'xatest';
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO mytable (i) VALUES(10);
Query OK, 1 row affected (0.04 sec)
mysql> XA END 'xatest';
Query OK, 0 rows affected (0.00 sec)
mysql> XA PREPARE 'xatest';
Query OK, 0 rows affected (0.00 sec)
mysql> XA COMMIT 'xatest';
Query OK, 0 rows affected (0.00 sec)
식별자 자리의 xid 는 세 조각입니다.
| 조각 | 뜻 | 기본값 |
|---|---|---|
gtrid |
전역 트랜잭션 식별자 | 없습니다. 필수입니다 |
bqual |
브랜치 한정자 | 빈 문자열 |
formatID |
형식 식별자 | 1 |
gtrid 와 bqual 은 각각 64바이트까지의 문자열 리터럴이어야 합니다. gtrid 는 모든 전역
트랜잭션에 걸쳐 전역으로 유일해야 합니다. bqual 은 같은 전역 트랜잭션 안의 XA 트랜잭션마다
달라야 합니다.
실패
깨지는 자리는 둘로 갈립니다. 하나는 도중에 누가 죽는 것이고, 다른 하나는 아무도 안 죽었는데 준비 상태가 오래 남는 것입니다.
도중에 죽었을 때
Gray 는 재시작 시점에 복구 관리자(재시작한 조정자·참가자 쪽에서 복구를 맡는 절차)가 가진 것이 로그와 비휘발성 저장소뿐이라고 적습니다. 조정자가 재시작할 때는 로그에 어느 레코드가 있느냐를 순서대로 확인해서 판정을 내립니다 — 아래 세 갈래는 서로 배타적이고, 위에서부터 확인한 결과로 그중 하나만 골라집니다.
flowchart TD
S["조정자 재시작 — 로그를 읽는다"] --> Q1{"PHASE12_COMMIT 이 있나"}
Q1 -->|없다| A["전원에게 ABORT 브로드캐스트"]
Q1 -->|있다| Q2{"COORDINATOR_COMPLETE 가 있나"}
Q2 -->|없다| C["COMMIT 을 다시 브로드캐스트하고 확인을 기다린다"]
Q2 -->|있다| I["그 트랜잭션을 무시한다"]
PHASE12_COMMIT 이 로그에 없으면 커밋 메시지보다 먼저 동기로 쓰이는 이 레코드 자체가 없다는
뜻이라 아무도 커밋하지 않은 상태이고, 재시작은 전원에게 취소를 브로드캐스트합니다.
PHASE12_COMMIT 은 있는데 COORDINATOR_COMPLETE 가 없으면 커밋을 알리는 도중에 죽은
것이므로 COMMIT 을 다시 브로드캐스트하고 확인을 기다립니다. COORDINATOR_COMPLETE 까지
있으면 이미 끝난 트랜잭션이라 재시작은 그것을 무시합니다.
참가자 쪽 재시작은 따로 갈립니다.
| 언제 | 어떻게 되나 |
|---|---|
| 참가자가 1단계에서 취소하거나 죽는다 | 조정자가 응답이 없다는 것을 타임아웃(앞서 나온 시간 제한과 같은 것입니다)으로 감지하고 트랜잭션 전체를 취소합니다 |
| 참가자가 2단계에서 죽는다 | 재시작할 때 복구 관리자가 조정자에게 다시 할지 되돌릴지 묻습니다. 1단계에서 로그에 충분히 적어 두었으므로 어느 쪽으로든 갈 수 있습니다 |
| 참가자 로그에 찬성이 강제로 쓰이지 않았다 | 그 트랜잭션은 취소됩니다 |
참가자가 이미 찬성을 답한 뒤라면 이야기가 달라집니다. Gray 의 참가자 절차는 찬성을 답한 다음 판정을 기다립니다. 재시작한 참가자의 로그에 찬성 레코드가 있으면 복구 관리자가 조정자에게 커밋됐는지 취소됐는지 묻고 그대로 따라갑니다. 판정이 오기 전까지 그 참가자는 트랜잭션이 쥔 잠금을 계속 들고 있습니다.
준비 상태로 남았을 때
PostgreSQL 문서는 트랜잭션을 준비 상태로 오래 두는 것이 현명하지 않다고 적습니다. 그 상태가
길어지면 VACUUM 이 저장 공간을 회수하는 일을 방해하고, 극단적인 경우에는 트랜잭션 ID
순환을 막기 위해 데이터베이스가 멈출 수도 있습니다. 그 트랜잭션이 들고 있던 잠금도 계속
쥐고 있습니다. 문서가 말하는 원래 용도는 외부 트랜잭션 관리자가 다른 데이터베이스들도 커밋
준비가 됐다고 확인하는 즉시 준비된 트랜잭션을 보통 커밋하거나 되돌리는 것입니다.
그래서 이 기능은 기본으로 꺼져 있습니다. max_prepared_transactions 는 동시에 준비 상태로
있을 수 있는 트랜잭션 수의 상한이고, 기본값인 0 이면 준비된 트랜잭션 기능 자체가 꺼집니다.
이 값은 서버 시작 시점에만 정할 수 있습니다. 준비된 트랜잭션을 추적하고 제때 닫아 주는 외부
트랜잭션 관리자를 세워 두지 않았다면, PostgreSQL 문서는 이 값을 0 으로 두는 편이 낫다고
적습니다. 반대로 쓰기로 했다면 세션마다 준비된 트랜잭션 하나를 걸 수 있도록
max_connections 이상으로 두고 싶어질 것이라고 덧붙입니다. 대기 서버를 함께 굴린다면 주
서버와 같거나 그보다 큰 값이어야 하고, 아니면 대기 서버에서 질의가 허용되지 않습니다.
남은 것을 찾는 창구는 따로 있습니다. PostgreSQL 은 pg_prepared_xacts 뷰가, MySQL 은
XA RECOVER 문이 그 자리입니다. XA RECOVER 는 PREPARED 상태인 XA 트랜잭션들의 정보를
돌려주며 XA_RECOVER_ADMIN 권한을 요구합니다.
준비 자체가 실패하는 경우도 있습니다. PostgreSQL 에서 PREPARE TRANSACTION 이 어떤 이유로든
실패하면 그것은 ROLLBACK 이 되어 현재 트랜잭션이 취소됩니다. 임시 테이블이나 세션 임시
네임스페이스를 건드린 트랜잭션, WITH HOLD 커서를 만든 트랜잭션, LISTEN·UNLISTEN·NOTIFY
를 실행한 트랜잭션은 현재로서는 준비할 수 없습니다. 그 기능들이 현재 세션에 너무 단단히
묶여 있기 때문입니다.
보장과 가정
보장은 하나입니다. Gray 는 이 알고리즘의 순 효과가 모든 참가자가 커밋하거나 아무도 커밋하지 않는 것이라고 적습니다. 원자성입니다. 어느 참가자가 잘못된 방향으로 행진하는 일이 크래시나 메시지 유실로 일어나지 않는다는 것을 납득하려면 꽤 긴 분석이 필요하다는 말도 같이 적혀 있습니다.
그 보장은 아래 전제들 위에 서 있습니다.
| 가정 | 근거 | 깨지면 |
|---|---|---|
| 참가자가 찬성을 답하기 전에 undo/redo 로그를 비휘발성 저장소로 강제로 내린다 | Gray 의 참가자 절차. MySQL 문서도 각 자원 관리자가 브랜치의 동작을 안정 저장소(비휘발성 저장소와 같은 뜻)에 기록하는 것이 대개 이 단계의 뜻이라고 적습니다 | 재시작한 참가자가 다시 하지도 되돌리지도 못합니다 |
| 조정자가 커밋 메시지를 보내기 전에 결정을 로그에 동기로 적는다 | Gray 의 조정자 절차 | 조정자 재시작이 무엇을 브로드캐스트할지 정할 근거를 잃습니다 |
| 재시작 시점에 로그가 남아 있다 | Gray — 복구 관리자가 가진 것은 로그와 비휘발성 저장소뿐입니다 | 위 두 판정 규칙이 전부 서지 않습니다 |
| undo 와 redo 가 멱등이다 | Gray 는 2단계에서 죽은 참가자를 어느 쪽으로든 완료시키려면 이것이 필요하다고 적습니다 | 복구가 같은 동작을 두 번 적용해도 같은 결과가 안 됩니다 |
| 메시지 수에 유한한 상한을 두지 않는다 | Gray 는 이 제약을 풀어야 해가 가능하다고 적습니다 | 두 장군 문제로 돌아가고 해가 없어집니다 |
메시지 수를 풀어 준 대가는 시간으로 돌아옵니다. Gray 는 이 프로토콜이 임의로 많은 메시지를 요구할 수 있으며, 대개는 몇 개면 되고 때로는 더 들며, 측도가 0(수학에서 일어날 확률이 사실상 0이라는 뜻으로 쓰는 표현)인 극히 드문 경우에는 무한히 많은 메시지가 든다고 적습니다.
지속성도 마찬가지로 절대적이지는 않습니다. PostgreSQL 문서는 준비된 트랜잭션의 상태가 전부 디스크에 저장되고, 커밋을 요청하기 전에 데이터베이스가 크래시하더라도 매우 높은 확률로 커밋에 성공할 수 있다고 적습니다. 보장한다고 적혀 있지는 않습니다.
조정자가 안 돌아오면 문제가 되는 것은 시간입니다. 결말은 이미 1단계 끝에 정해져 있으므로 뒤집히지는 않습니다. 다만 그 결말을 전달받지 못한 참가자는 판정을 기다리며 잠금을 계속 쥡니다. 위에서 다룬 단일 단계 커밋의 In Doubt 상태도 이런 자리에서 나옵니다 — 다만 참가자가 아니라 조정자 쪽입니다. 조정자가 결말을 정할 권리를 참가자에게 넘겼다가 그 결말을 확인하지 못하게 되는 경우입니다. 같은 명세는 일시적 장애 뒤에 두 참가자가 연결을 다시 세우고 트랜잭션 결말에 대한 시각을 맞추는 과정을 복구라고 부릅니다.
관련 항목
위 — 2단계 커밋이 지키는 성질
아래 — 프로토콜을 이루는 역할과 기록
조정자 · 참가자 · 트랜잭션 관리자 · 자원 관리자 · 브랜치 · 로그 · 레코드 · 메시지 · 잠금 · 비휘발성 저장소
옆 — 이웃한 절차와 판정
단일 단계 커밋 · 중첩 2단계 커밋 · 추정 취소 · 두 장군 문제 · 타임아웃 · 복구 · 복구 관리자 · In Doubt
쓰이는 곳 — 이것을 구현한 제품·명세
PostgreSQL · MySQL · XA · MS-DTCO
명령이 건드리는 데이터베이스 개념
다른 이름: 2PC · two-phase commit · Two-Phase Commit Protocol