# 三阶段提交（3PC）

> 引入一个作为**协调者（coordinator）**&#x7684;组件来统一掌控所有**参与者（participant）**&#x7684;操作结果，并最终指示这些节点是否要把操作结果进行真正的提交。

## 协议说明

<mark style="color:blue;">**三阶段提交（Three Phase Commit）**</mark>，是 2PC 的改进版，其**将二阶段提交协议的“提交事务请求”过程一分为二，形成了由&#x20;**<mark style="color:blue;">**CanCommit**</mark>**、**<mark style="color:blue;">**PreCommit**</mark>**&#x20;和&#x20;**<mark style="color:blue;">**doCommit**</mark>**&#x20;三个阶段组成的事务处理协议。**

### 阶段一：CanCommit

1. **事务询问**。协调者向所有的参与者发送一个包含事务内容的 canCommit 请求，询问是否可以执行事务提交操作，并开始等待各参与者的响应。
2. **各参与者向协调者反馈事务询问的响应**。参与者在接收到来自协调者的 canCommit 请求后，正常情况下，如果其自身认为可以顺利执行事务，那么会反馈 Yes 响应，并进入预备状态，否则反馈 No 响应。

### 阶段二：PreCommit

**在阶段二中，协调者会根据各参与者的反馈情况来决定是否可以进行事务的 PreCommit 操作**，正常情况下，包含两种可能：

* **执行事务预提交：**&#x5047;如协调者**从所有的参与者获得的反馈都是 Yes 响应**，那么就会执行事务预提交。
  1. **发送预提交请求**。协调者向所有参与者节点发出 preCommit 的请求，并进入 Prepared 阶段。
  2. **事务预提交**。参与者接收到 preCommit 请求后，会执行事务操作，并将 **Undo** 和 **Redo** 信息记录到事务日志中。
  3. **各参与者向协调者反馈事务执行的响应**。如果参与者成功执行了事务操作，那么就会反馈给协调者 Ack 响应，同时等待最终的指令：**提交（commit）**&#x6216;**中止（abort）**。
* **中断事务：**&#x5047;如**任何一个参与者向协调者反馈了 No 响应**，或者在**等待超时**之后，协调者尚无法接收到所有参与者的反馈响应，那么就会中断事务。
  1. **发送中断请求**。协调者向所有参与者节点发出 abort 请求。
  2. **中断事务**。**无论是收到来自协调者的 abort 请求，或者是在等待协调者请求过程中出现超时，参与者都会中断事务。**

### 阶段三：doCommit

**该阶段将进行真正的事务提交**，会存在以下两种可能的情况：

* **执行提交：**
  1. **发送提交请求**。进入这一阶段，假设协调者处于正常工作状态，并且它接收到了来自所有参与者的 Ack 响应，那么它将从“预提交”状态转换到“提交”状态，并向所有的参与者发送 doCommit 请求。
  2. **事务提交**。参与者接收到 doCommit 请求后，会正式执行事务提交操作，并在完成提交之后释放在整个事务执行期间占用的事务资源。
  3. **反馈事务提交结果**。参与者在完成事务提交之后，向协调者发送 Ack 消息。
  4. **完成事务**。协调者接收到所有参与者反馈的 Ack 消息后，完成事务。
* **中断事务：**&#x8FDB;入这一阶段，假设协调者处于正常工作状态，并且有任意一个参与者向协调者反馈了 No 响应，或者在**等待超时**之后，协调者尚无法接收到所有参与者的反馈响应，那么就会中断事务。
  1. **发送中断请求**。协调者向所有的参与者节点发送 abort 请求。
  2. **事务回滚**。参与者接收到 abort 请求后，会利用其在阶段二中记录的 Undo 信息来执行事务回滚操作，并在完成回滚之后释放在整个事务执行期间占用的资源。
  3. **反馈事务回滚结果**。参与者在完成事务回滚之后，向协调者发送 Ack 消息。
  4. **中断事务**。协调者接收到所有参与者反馈的 Ack 消息后，中断事务。

**一旦进入阶段三，可能会存在以下两种故障：**

* **协调者出现问题。**
* **协调者和参与者之间的网络出现故障。**

无论出现哪种情况，最终都会**导致参与者无法及时接收到来自协调者的 doCommit 或是 abort 请求**，针对这样的异常情况，**参与者都会在等待超时之后，继续进行事务提交**。

## 优缺点

三阶段提交协议的**优点**：**相较于二阶段提交协议，三阶段提交协议最大的优点就是降低了参与者的阻塞范围，并且能够在出现单点故障后继续达成一致。**

三阶段提交协议的**缺点**：三阶段提交协议在去除阻塞的同时也引入了新的问题，那就是在参与者接收到 preCommit 消息后，如果网络出现分区，此时协调者所在的节点和参与者无法进行正常的网络通信，在这种情况下，该参与者依然会进行事务的提交，这必然出现数据的不一致性。
