Java面经系列之分布式篇(一)分布式理论基础
目录
一、CAP理论
二、BASE理论
三、数据一致性理论(副本、协调者、分布式协议2PC 3PC、选举、逻辑时钟)
1、副本
2、协调者
3、分布式协议
4、选举、多数派、租约
5、逻辑时钟
四、数据一致性模型
1、强一致性
2、弱一致性
3、最终一致性
4、最终一致性模型的变种
CAP理论是指在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得。
BASE是Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致性)三个短语的缩写。BASE理论是对CAP理论中一致性(A)和可用性(C)权衡的结果,来源于对大规模互联网系统分布式实践的结论。
由BASE理论,衍生出了很多数据一致性的解决方案,常见的有三种:强一致性、弱一致性、最终一致性。
BASE理论面向的是大型高可用可扩展的分布式系统,和传统的事物ACID特性是相反的,它完全不同于ACID的强一致性模型,而是通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致状态。但同时,在实际的分布式场景中,不同业务单元和组件对数据一致性的要求是不同的,因此在具体的分布式系统架构设计过程中,ACID特性和BASE理论往往又会结合在一起。
数据一致性是指:在分布式系统中,对每个节点的数据更新,整个集群都需要知道更新,并且是一致的。面临的问题:
常见的数据一致性解决方案如下,
当前一般通过复制技术进行分布式系统的一致性的保证,不同的数据节点由于网络延迟、操作链中一环失败等原因,往往造成数据不一致的问题。
引入协调者的原因是在分布式操作者,需要一个中间者能够感知到该事务在其他环境中的执行情况,这样好决定在当前机器上是需要提交还是回滚。一般情况下,某一个数据库无法知道其他数据库在做什么,在一个分布式事务环境中,交易中间件是必须的,由他来通知和协调数据库提交或者回滚;而本地也将所做的操作影射到全局事务中。
常见的分布式协议有:2PC(两阶段提交)、3PC(三阶段提交),他们也不能根除数据不一致性问题。
3.1 2PC(两阶段提交)
我们将提议的节点称为协调者(coordinator),其他参与决议节点称为参与者(participants, 或cohorts)。两阶段为:
3.2 3PC(三阶段提交)
3PC是2PC的改进版本,引入了超时机制,加入一个新的CanCommit阶段。三阶段为:
4.1 选举
Bully算法是最常见的选举算法,其要求每个节点对应一个序号,序号最高的节点为leader。leader宕机后次高序号的节点被重选为leader。
4.2 多数派
在网络分化的场景下以上Bully算法会遇到一个问题,被分隔的节点都认为自己具有最大的序号、将产生多个leader,这时候就需要引入多数派(quorum)。多数派的思路在分布式系统中很常见,其确保网络分化情况下决议唯一。多数派的原理说起来很简单,假如节点总数为2f+1,则一项决议得到多于 f 节点赞成则获得通过。leader选举中,网络分化场景下只有具备多数派节点的部分才可能选出leader,这避免了多leader的产生。
4.3 租约
选举中很重要的一个问题,以上尚未提到:怎么判断leader不可用、什么时候应该发起重新选举?最先可能想到会通过心跳判别leader状态是否正常,但在网络拥塞或瞬断的情况下,这容易导致出现双主。租约(lease)是解决该问题的常用方法,其最初提出时用于解决分布式缓存一致性问题,后面在分布式锁等很多方面都有应用。
租约的原理同样不复杂,中心思想是每次租约时长内只有一个节点获得租约、到期后必须重新颁发租约。租约机制确保了一个时刻最多只有一个leader,避免只使用心跳机制产生双主的问题。在实践应用中,zookeeper等可用于租约颁发。
5.1 物理时钟 vs 逻辑时钟
可能有人会问,为什么分布式系统不使用物理时钟记录事件?每个事件对应打上一个时间戳,当需要比较顺序的时候比较相应时间戳就好了。这是因为现实生活中物理时间有统一的标准,而分布式系统中每个节点记录的时间并不一样,即使设置了NTP时间同步节点间也存在毫秒级别的偏差。因而分布式系统需要有另外的方法记录事件顺序关系,这就是逻辑时钟(logical clock)。
5.2 Lamport时间戳
Lamport时间戳帮助我们得到事件顺序关系。有这几个特点,
5.3 Vector clock
有一种顺序关系不能用Lamport时间戳很好地表示出来,那就是同时发生关系(concurrent)。Vector clock是在Lamport时间戳基础上演进的另一种逻辑时钟方法,它通过vector结构不但记录本节点的Lamport时间戳,同时也记录了其他节点的Lamport时间戳。
5.4 Version vector
Version vector的实现与Vector clock非常类似,目的用于发现数据冲突。
当更新操作完成之后,任何多个后续进程或者线程的访问都会返回最新的更新过的值。这种是对用户最友好的,就是用户上一次写什么,下一次就保证能读到什么。但是这种实现对性能影响较大。
系统并不保证续进程或者线程的访问都会返回最新的更新过的值。系统在数据写入成功之后,不承诺立即可以读到最新写入的值,也不会具体的承诺多久之后可以读到。但会尽可能保证在某个时间级别(比如秒级别)之后,可以让数据达到一致性状态。
弱一致性的特定形式。系统保证在没有后续更新的前提下,系统最终返回上一次更新操作的值。在没有故障发生的前提下,不一致窗口的时间主要受通信延迟,系统负载和复制副本的个数影响。DNS是一个典型的最终一致性系统。
上述最终一致性的不同方式可以进行组合,例如单调读一致性和读己之所写一致性就可以组合实现。并且从实践的角度来看,这两者的组合,读取自己更新的数据,和一旦读取到最新的版本不会再读取旧版本,对于此架构上的程序开发来说,会少很多额外的烦恼。
为了解决分布式的一致性问题,在长期的研究探索过程中,涌现出了一大批经典的一致性协议和算法,其中比较著名的有二阶段提交协议,三阶段提交协议和Paxos算法。