随着分布式的概念被提出,越来越多的企业开始采用大量的廉价机器来代替单个的大型超级计算机,与之而来的就是各种分布式的问题,像单点登录、分布式事务、分布式一致性等等,今天就来说一下分布式一致性问题
我们传统的单机事务,可以清楚的知道我们的事务是否执行成功或者失败,但是,当我们的事务跨越多个节点的时候,为了满足我们事务的ACID特性,我们就需要一个协调者的角色来统一调控各个节点的事务执行逻辑
基于这个思想,产生了各种分布式事务的解决方案
基于数据库资源层面
基于数据库资源层面实现方案,由于存在着多个事务,我们需要存在一个角色管理多个事务,通常将这个角色称为协调者, 事务参与者称为参与者, 参与者和协调者一般会遵循某种特定的协议,基于协调者与参与者的思想设定,分别提出了2PC、3PC实现XA分布式事务。
2PC
优点 : 简单、容易实现(😳简单带了许多缺点)
缺点 : 个人觉得 2PC 实现得还是比较鸡肋的…因为仅仅只解决了事务的原子性
同步阻塞 : 每一个节点在2pc阶段,都会进行阻塞,来等待其他节点的结果,会很消耗我们分布式系统的性能
单点问题 : 😬明眼人都可以看出,协调者在我们的协议中所占的地位是特别高的,但是,协调者只有一个,也就是说,如果我们的协调者出现故障的话,我们的整个系统就无法运行,更可怕的是 😱,想一想当我们的协调者在第二阶段commit阶段挂掉了,所有的参与者都会持有事务资源,不会释放,并且无法继续完成事务
数据不一致 : 当我们的协调者,在第二阶段发送了一部分commit命令之后挂掉了,就会导致我们的参与者一部分执行了事务,一部分没有执行,就会导致我们整个系统的数据不一致
太过保守 : 没有健全的容错机制,也就是说,任何一个节点的故障都会导致整个事务的失败
3PC
- canCommit(是否可以提交) : 协调者向参与者询问是否可以进行事务的提交
- preCommit(预提交) :若所有的参与者都可以进行事务的提交,协调者下达PreCommit指令,参与者锁定资源,进行事务执行(注意,只是执行,并不会提交),并将结果记录redo/undo 日志中,并等待最终命令doCommit
若部分参与者返回否认信息或协调者等待超时,这种情况下协调者认为事务无法正常执行,下达中断命令,各个参与者根据日志返回原始状态并且退出PreCommit - DoCommit (最终提交) : 若第二阶段全部回应ack,则下达doCommit,进行事务的最终提交,并释放资源。否则下达rollback回滚指令,所有事务回滚
优点 : 3PC引入超时机制减少了事务阻塞,解决单点故障,在第三阶段,一旦参与者无法接收到协调者的信号并等待超时时,参与者会默认执行commit,释放资源
缺点 : 三阶段提交仍然不能解决数据的一致性问题,若协调者发送回滚命令,由于网络问题,部分参与者无法收到rollback指令,那么就会选择默认提交事务,造成了一部分回滚另一部分提交的尴尬局面,造成事务的不一致。
PAXOS
这个算法是Leslie Lamport提出的基于消息传递并具有高度容错性的一致性协议,目前也是解决分布式一致性的最有效的解法
这里需要以一个著名的故事开头,可能有的小伙伴已经知道了, 那就是著名的拜占庭将军问题
传说啊,拜占庭帝国有许多的军队,不同军队的将军之间需要制定统一的作战计划,从而做出进攻或者是撤退的决定。同时呢,各个将军在地理位置上都是分隔开的,只能有各个军队的通信员来进行消息的传输。然而,在所有的通信员中可能会有叛徒,这些叛徒可以随意的撰改消息,以达到欺骗将军的目的
这个故事告诉我们,从理论来说,要想在异步系统的不可靠信道上达成一致性是不可能的, 所以,我们对一致性的研究过程中,都是假设信道是安全的,而事实上,我们系统大多在一个局域网下部署,所以很少会有消息撰改的现象发生------- 因此,在实际的工程中,可以假设没有拜占庭将军问题,即也就是消息都是可靠的,那么这种情况下,需要怎样来保证消息的可靠性呢?
我们的paxos协议登场
通过一个简单的流程来解释它
paxos 是一个精妙而又强大的协议,从过程来看,正如作者所说的,是一个**“简单”**的协议,但是,lamport在论文中是以一个讲述paxos小岛上议会的方式引出的算法,使其直接在工程领域实施变得颇具难度。因此,可以看到市场上有许多的paxos的变种,我认为比较典型的就是zookeeper的ZAB协议。
基于业务层面
TCC (Try Confirm/Cancel)
为了降低锁的粒度,提高并发性能,我们将数据库层面的分布式事务提高到了应用层,锁的粒度直接由应用层把控,它的本质是一个补偿机制
其核心思想是将一个操作分为三个操作, 分别为 try , commit , cancel , 为了满足网络不可靠下的可靠性,我们的commit/cancel操作必须实现幂等性
下面说一下各个操作分别要做的事情 :
- try : 完成所有业务检查,预留必须业务资源
- Confirm : 执行业务,满足幂等性
- Cancel : 释放在try中锁定的资源,满足幂等性
一个大致的流程
它的缺点就是对我们的业务代码侵入有点大
以上就是我们常见的一些基础分布式一致性算法,后续将会聊聊那些在具体工程实践当中的分布式算法
Respect!