推荐学习
- 肝了30天,整出这份[分布式宝典:限流+缓存+通讯],秋招跳槽有望
- 消息中间件合集:MQ(ActiveMQ/RabbitMQ/RocketMQ)+Kafka+笔记
- 2020年后想跳槽?MQ、ZK、Nginx、Kafk等分布式技术你都掌握了?
一、引言
随着业务的增长,单体架构发展为分布式架构,大大提升了业务的处理能力,但同时也带来了很多单体架构不存在的问题,如:
- 各节点之间网络通信的异常以及因其引起的脑裂问题(网络分区)。
- 引出“三态”。在单体架构中只会存在“成功”或“失败”两种结果,但是在分布式架构中由于网络异常将会出现“未知”的结果,即请求丢失或者响应丢失,导致客户端超时。
- 各节点会发生故障。
- 分布式事务以及数据一致性。
- 各节点的配置和地址的维护。一台机器我们可以很容易的进行管理,但是在分布式下存在很多台机器共同协作,不可能再由人工手动维护。
本篇,主要讲述数据一致性的解决方案以及服务的协调治理工具Zookeeper基本概念。
二、从ACID到CAP/BASE
事务的ACID特征在单体架构中已经得到很好地验证和实践,但是在分布式架构中,是由多个独立的事务来构成一个完整的分布式事务,我们无法实现一套严格遵循ACID的分布式事务,因为数据的一致性和系统的可用性是冲突的,不存在完美的解决方案。但由于业务的需求和推动,逐渐出现了诸如CAP、BASE这样的经典理论,基于这样的理论我们可以构建出一个大致兼顾二者的分布式系统。
- CAP理论是说一个分布式系统不可能同时满足一致性(Consistency)、可用性(Availability)以及分区容错性(Partion tolerance),只能同时满足其中两个。而在分布式系统中,P是必须满足的,否则就不存在分布式了。因此,我们需要在C和A之间权衡。
- Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致性)简称BASE理论,它是对CAP理论的改进,权衡了其中的可用性和一致性。其核心思想是即使无法做到强一致性,但每个业务都可以根据自己的特点,采用适当的方式达到最终一致性。因为对于客户而言,拿到过时的数据总好过于网页都打不开,只要在一个可接受的时间内能保证最终数据是正确的即可。
三、分布式一致性协议
由于在设计分布式架构时,需要根据业务反复权衡可用性和数据一致性,因此产生了一系列的一致性协议算法,其中最著名的就是二阶段提交(2PC)、三阶段提交(3PC)和Paxos算法。
1. 2PC和3PC
在分布式结构中,各节点能明确知道自身的事务执行结果,但是无法直接获取其它节点的事务执行结果。那要如何保证事务执行的一致性呢?我们可以引入一个协调者来统一调度所有节点,被调度的节点称为参与者。就像一支分为很多个小分队的军队,统一受将军的分配调度,如果没有“将军”这样一个“支配者”,那么这个军队就是一盘散沙,根本无法协同作战。分布式架构也是如此,协调者负责调度参与者的行为,并最终决定是否真正的提交事务。在这个思想上,衍生出了2PC和3PC协议。
2PC
2PC将事务提交分为两个阶段:发起事务请求和事务提交/回滚
发起事务请求
- 首先协调者向各参与者发送事务内容,询问是否可以执行事务提交,并等待参与者的反馈。
- 然后各参与者开始执行事务,并记录事务日志信息。
- 最后各参与者向协调者反馈事务执行的结果,成功或者失败。
事务提交/回滚
在该阶段中,协调者根据参与者的反馈决定是否真正提交事务,只要有一个参与者反馈的是“失败”或者等待反馈超时,那么协调者就会通知各参与者回滚之前的事务操作;否则,通知参与者提交事务。参与者执行完成后会反馈协调者一个ACK,协调者收到所有的参与者ACK后,完成事务的提交或中断。
以上就是2PC的执行过程,其中一阶段可以看作是一个投票过程,二阶段则是执行投票的结果。因为需要等待参与者的“全票通过”,因此2PC是一个强一致性的协议算法。
2PC原理简单,实现容易,但同时也存在很多的问题:
- 同步阻塞:在整个二阶段提交的过程中,参与者在释放占用资源之前(提交或终止完成),是处于同步阻塞的,无法处理其它任何操作,极大地影响了系统的性能。
- 单点故障:由上可知,协调者在整个过程中非常的重要,一旦出现问题,整个协议就无法运转了。
- 数据不一致:当在第二个阶段,协调者正在发出提交请求,此时网络出现故障或者协调者自身崩溃导致只有一部分参与者收到提交请求,那么数据就会出现不一致。
- 过于保守:在事务询问阶段,如果任一参与者在反馈协调者之前出现故障而导致协调者无法收到反馈,那么协调者就会一直处于阻塞状态,只能通过自身的超时机制来判断是否要中断事务。
3PC
3PC则是对2PC的改进,将发起事务请求阶段一分为二,因此包含了三个阶段:事务询问(canCommit)、事务预提交(preCommit)和提交事务(doCommit)。
canCommit
- 协调者向所有参与者发送一个包含事务内容的询问请求,等待参与者的反馈。
- 参与者收到请求后,根据自身情况返回"YES"或"NO"。
preCommit
协调者根据参与者的反馈情况来通知参与者预提交事务或者中断事务:
- 预提交事务:协调者收到的都是“YES”反馈,就会通知参与者进行事务的预提交,并记录事务日志,参与者执行预提交完成后,将结果反馈给协调者。
- 中断事务:若一阶段中任一参与者反馈的是“NO”,或者协调者等待反馈超时,那么协调者就会发出中止请求,此时无论参与者是收到中止请求或是等待请求超时,参与者都会中断事务。
doCommit
协调者根据二阶段参与者的反馈来通知参与者提交事务或者回滚事务:
- 提交事务:二阶段中所有参与者预提交事务成功,则在此阶段真正地提交事务。
- 回滚事务:二阶段中任一参与者预提交事务失败,则在此阶段根据事务日志回滚事务。
需要注意的是,在此阶段,可能会出现以下故障:
- 协调者出现故障
- 协调者和参与者之间通信故障
无论是哪种故障,都是导致参与者无法接收到协调者发出的请求,针对这种情况,参与者在等待请求超时后,都会继续提交事务(不能回滚,因为协调者可能已经提交事务,若参与者回滚事务就会导致数据不一致)。
通过以上过程,我们可以发现,3PC相较于2PC的优点:
- 降低了阻塞的范围,3PC要到阶段二才会出现阻塞,而2PC在整个提交过程中都是阻塞的。
- 在阶段三出现单点故障后能够保证数据的一致性
但在优化阻塞问题的同时带来了新的问题,当参与者收到preCommit请求后出现网络分区,那么断开连接的参与者会继续提交事务,而协调者由于未收到全部参与者的“YES”反馈,就会向保持连接的参与者发出中断事务的请求,导致数据出现不一致。
因此,我们可以看出无论是2PC还是3PC都无法完全解决数据一致性问题,并且整个事务提交过程太过保守,导致性能并不是很好。所以,Paxos算法也就出现了。
2. Paxos
Paxos算法被认为是唯一的一致性算法,而其它的协议算法都是它的不完整版,其复杂难以理解程度是公认的,因此,小编这里不花费过多的时间来表述,感兴趣的读者可以去了解其诞生背景和原论文《Paxos Made Simple》。(注:Paxos发展历史是很有意思的,该篇论文是由于作者第一篇论文太过晦涩几乎无人理解,不得不用通俗易懂的语言重新描述而发表的)
3. ZAB协议
Zookeeper Atmoic Broadcast(ZAB,Zookeeper的原子消息广播协议),一种基于Paxos算法实现的协议,但又和Paxos不完全相同,是Zookeeper保证数据一致性的核心算法。这里只是列举,后文进行阐述。
四、Zookeeper初探
![adbfcf4d0b1792d97f6bdfb80cdb548d.png](https://i-blog.csdnimg.cn/blog_migrate/727174ccaf63b5a6f3e05ced5c9edd74.jpeg)
1. 简介
Zookeeper是一个开源的分布式协调服务组件,由雅虎公司创建。分布式应用程序可以基于它实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、分布式锁和队列等功能。它可以保证如下分布式一致性特性:
- 顺序一致性:同一客户端的事务请求按照“先入先出”的方式处理,保证了事务执行的顺序。
- 原子性:集群情况下,保证事务要么都被所有机器执行,要么都不执行,不存在部分执行部分不执行的情况。
- 最终一致性:客户端从服务端获取的数据不一定是实时最新的,但是能保证在一定的时间内服务端数据达到最终一致性,即客户端最终能获取到最新的数据。
- 共享视图:无论客户端连接的是哪个服务端,获取到的数据都是一样的,不存在特例。
- 可靠性:一旦一个事务被执行成功且正确的返回给了客户端,那么这个事务结果就会持久化存在并共享给所有服务器节点,除非有新的事务更改了该事务的结果。