三阶段提交协议是二阶段提交协议的改进,它把二阶段提交协议中的提交事务请求阶段进一步拆分成CanCommit、PreCommit和DoCommit三个阶段,并且在协调者和参与者中都引入了超时机制。
第一阶段有以下几个步骤。
canCommit
消息,询问是否可以执行事务提交操作,然后等待参与者的响应。Yes
并进入预备状态,否则反馈No
。与二阶段提交协议不同的是,在三阶段提交协议的第一个阶段中,参与者们不会执行事务,由于不会执行事务,因此不会对资源上锁,从而降低了阻塞的范围。
如果阶段一中的参与者都反馈Yes
,那么进入下面执行事务预提交的步骤。
preCommit
消息,并进入预提交状态。Ack
消息,并等待进一步的指令。相反,如果协调者收到一个No
反馈或者部分参与者反馈超时了,那么就执行中断事务的步骤。
abort
消息。abort
消息的参与者或者在等待协调者消息过程中超时的参与者执行事务的中断。如果阶段二中的参与者都反馈Ack
,那么执行下面的步骤。
doCommit
消息。doCommit
消息后就会正式提交事务。Ack
消息。Ack
消息后完成事务。如果阶段二中有一个参与者反馈了非Ack
消息或者反馈超时,那么执行以下步骤。
abort
消息。abort
消息的参与者进行事务的回滚。Ack
消息。Ack
消息后中断事务。在这一阶段中,如果因为某种原因导致参与者无法及时收到协调者发送的doCommit
或abort
消息,参与者在等待超时后会继续提交事务。
相比二阶段提交协议,三阶段提交协议减少了同步阻塞的时间,比如当协调者发生单点故障后,参与者们等待超时后会自动进行提交事务的操作。
缺点是虽然参与者的超时自动提交事务的机制减少了阻塞的时间,但也引发数据不一致的问题。比如发生网络分区后,一部分参与者收到了abort
消息从而进行事务回滚,而另一部分参与者因为分区原因没有收到abort
消息因此会提交事务,导致数据不一致。
三阶段提交协议虽然通过引入参与者的超时机制避免了二阶段提交协议中当参与者和协调者同时宕机后整个系统阻塞的风险,但是由于超时又引发了数据不一致的问题,因此并不是完美的解决方案。