分布式事务使用最多的是二阶段提交以及其变种,了解其优缺点可以帮助决定在分布式系统上是否采用事务
二阶段提交(2PC)
什么是2PC
二阶段提交本身比较简单,就是把分布式事务分成准备阶段
和提交阶段
两个阶段。目的很明确,就是尽可能晚地提交事务,让事务在提交前尽可能地完成所有能完成的工作,这样,最后的提交阶段将是一个耗时极短的微小操作,这种操作在一个分布式系统中失败的概率是非常小的,也就是所谓的“网络通讯危险期”非常的短暂,这是两阶段提交确保分布式事务原子性的关键所在。(唯一理论上两阶段提交出现问题的情况是当协调者发出提交指令后宕机并出现磁盘故障等永久性错误,导致事务不可追踪和恢复)。
2PC内容
协议的详细内容,网上很多,这里就给出两张图,就不做过多介绍了
缺点
同步阻塞问题 这是2PC存在的最明显也是最大的一个问题。执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。比如数据库事务使用锁实现隔离性,事务没有提交,就会一直占用锁资源,导致并发量很低,性能很差。
单点故障 由于协调者的重要性,一旦协调者发生故障。参与者会一直阻塞下去。尤其在提交阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)
数据不一致 在提交阶段,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这会导致只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据不一致性的现象。
二阶段无法解决的问题 协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。
太过保守 如果在协调者指示参与者进行事务提交询问的过程中,参与者出现故障而导致协调者始终无法获取到所有参与者的响应信息的话,这时协调者只能依靠其自身的超时机制来判断是否需要中断事务,这样的策略显得比较保守。换句话说,二阶段提交协议没有设计较为完善的容错机制,任意一个节点的失败都会导致整个事务的失败。
三阶段提交(3PC)
什么是3PC
与两阶段提交不同的是,三阶段提交有两个改动点。
- 引入超时机制。同时在协调者和参与者中都引入超时机制。
- 将2PC第一阶段一分为二,在CanCommit阶段中可以尽早给出事务是否可以执行的判断,占用资源很少,提高了吞吐量。
3PC的内容
协议的详细内容,网上很多,这里就给出一张图,就不做过多介绍了
2PC与3PC的区别
相对于2PC,3PC主要解决的单点故障问题,并减少阻塞,因为一旦参与者无法及时收到来自协调者的信息之后,他会默认执行commit。而不会一直持有事务资源并处于阻塞状态。但是这种机制也会导致数据一致性问题,因为,由于网络原因,协调者发送的abort响应没有及时被参与者接收到,那么参与者在等待超时之后执行了commit操作。这样就和其他接到abort命令并执行回滚的参与者之间存在数据不一致的情况。
提问
- 既然2PC可能出现数据不一致的情况,为什么又是强一致性协议呢?