分布式数据基础和分布式共识基础

目标

了解基础理论,Quorum ,CAP, BASE, PACELC, BASE, 一致性理论

算法:Paxos, Raft

分区

分类:水平分区,垂直分区

水平分区算法

1、范围分区

通过id范围对数据进行分区

优点查询范围简单,缺点容易分布不均

2、哈希分区:缺点

通过将键进行哈希运算,根据计算的值得到分区

优点:分布均匀,缺点:当增加或删除节点时,由于每个节点都需要一个对应的哈希值,需要改变哈希函数,将所有数据重新映射

3、一致性哈希

将哈希函数的输出值组织成抽象的圆环,然后将节点映射到圆环上,根据哈希值将数据映射到圆环上,数据存储在顺时针遇到的第一个节点上

相比于哈希分区,当添加删除节点时,只会影响部分数据;

但是容易发生数据分布不均匀,且当删除节点时,会导致大量数据转移到下一个节点,造成负载倾斜

解决方法:引入虚拟节点,一个节点对应的多个虚拟节点,并且性能高的机器可以映射更多个虚拟节点,承担更多的负载

分区的挑战

1、联合查询效率低,可能需要访问多个节点的数据

2、实现分布式事务比较困难

复制

复制的好处:减小RTT(有多个节点,往返更快),增强数据的安全性,增强吞吐量

单主复制

一个主节点

分为同步复制、异步复制、半同步辅助(一个节点同步,其他异步)

多主复制

多个主节点

由于多个节点执行写操作,在网络延迟情况下容易发生数据不一致问题

解决方法:

1、客户端解决冲突,将冲突数据返回给客户端,客户端自行更新(如淘宝的购物车)

2、最后写入胜利(LWW),给写入请求加上时间戳,发生冲突时选择最新的时间戳数据

3、因果关系跟踪:先发帖再回帖

无主复制

所以节点都写,对故障的容错更高,但是导致更多的冲突

基于Quorum的数据冗余机制解决

Quorum是保证数据冗余和最终一致性的算法

当共N个节点时,要求至少W个节点写入成功,并同时从R个节点读取数据,只要W + R > N 且 W > N /2,则读取值至少包含最新的值

证明:如果至少W个节点写入成功则至多N - W个节点不成功,则R > N-W时,至少能得到一个最新的值

W > N /2是为了保证串行化修改,不让一个节点同时执行两个不同的命令

W越大R越小读性能越好,W越小R越大写的性能越好

CAP/PACELC/BASE

CAP

C:一致性,A:可用性,P:分区容错性

CAP定理:对于一个分布式读写存储系统,只能同时满足两项

由于网络故障是必然发生的基本上选择CP/AP,要在一致性和可用性中取舍

不足:CAP定理忽略了网络延迟,而网络延迟是时刻存在的,而网络分区不会一致存在

PACELC

如果存在网络分区(P)则在可用性(A)和一致性(C)间取舍,否则(E)在延迟(L)和一致性(C)间取舍

因为没有网络分区,而肯定有延迟存在,这是如果直接返回则选择延迟,出现数据不一致情况;

如果不返回则降低了可用性,保证了一致性

因此大多数系统选择AP/EL,PC/EC

BASE

基本可用 + 软状态 + 最终一致性

为了高可用放弃强一致性,选择最终一致性

最终一致性:可能会有网络分区/延迟,数据没有及时同步,但仍然允许继续读写,在最终的某个时刻,系统保证所有副本都是同步的

一致性模型

一致性从强到弱的模型

线性一致性

非严格定义:线性一致性的系统要像单一节点一样工作,并且所有操作都是原子的

严格定义:给定一个执行历史,执行历史可以拓展为多个顺序历史,只要有一个合法的顺序历史,那么就是线性唯一的

注:并发操作即有重叠的操作,可以任意顺序排列

约束条件:顺序记录要和全局时钟的顺序一致

代价:全局时钟

顺序一致性

顺序一致性允许不同客户端间的操作改变先后顺序

和线性一致性的主要区别:没有全局时间的限制,只关注局部的顺序

因果一致性

体现了一种A在B之前的因果关系

最终一致性

在最终时刻系统到达稳定的状态,即在最终状态,系统不执行写操作,读操作结果相同

Paxos

Basic-Paxos只决议出一个共识的值,之后都继续使用这个提案值

主要包括两个阶段

一:

  • 提议者向接收者发送提案编号Prepare

  • 接收者收到后判断,如果Prepare中的提案编号大于之前接收的所有提案编号则Promise响应

特别注意:如果接收者之前接受了某个提案,那么响应还会将上一次提案的编号和值一起发送(一直用一个提案值)

二:

  • 提议者像接收者发起Accept()请求,带上提案值和提案编号,如果之前收到的Promise()中有提案值,则使用提案编号最大的提案值,否则自己决定提案值

  • 接收者收到Accept()后检查提案编号,如果没有比该编号更大的提案,则接受该提案并保存

活锁问题:

如果提议者A在1a阶段发送提案给接收者,在接收者Accept之前,提议者B又在1a阶段发送提案给接收者

那么因为第二个提案编号大于第一个提案编号,接收者无法accept第一个提案

如果在接收到第二个提案后。有没有Accept,提议者A又发送新的提案,循环下去,则导致接收者一直在决定提案编号的过程中

解决方法:引入随机超时,当某个提议者发现提案没有被成功接收,则等待一个随机超时时间,让出机会

实验:用Go语言实现Basic-Paxos算法

Raft

raft的三个状态:领导者、跟随者、候选者

raft算法选出领导者后进入一个新的任期,任期分为:选举过程 + 正常运行过程

领导者选举

节点先处于候选者状态,向自己和其他节点索要选票,当受到超过半数的选票后成为领导者,或收到领导者的心跳包(空的appendEntries)时成为追随者,如果经过超时时间两种情况都没发生则开始新一轮的选举。

每个节点在同一任期只能投一次票,然后拒绝其他候选者的请求

注:超时时间是为了避免活锁,超过一半的选票是为了只有一个领导者

日志复制

日志的每个条目包括:索引、任期号、命令

raft通过索引和任期号唯一标识一条日志记录,如果一条日志记录被存储在半数节点中则认为该记录已提交

raft通过appendEntries来复制日志和 心跳包共用一个RPC,但发送心跳消息时不包含日志

raft算法通过检查最新日志消息的前一条记录的索引和任期是否一致,如果一致则追加命令,满足安全性

领导者更替

候选者在索要投票时,加上自己最后一条日志的任期和索引

收到投票的节点要比较谁的任期最新,然后比较谁的日志最完整,如果不如自己则拒绝投票

这样确保领导者在半数节点中拥有最完整的日志

日志延迟提交

延迟提交原因:如果超过半数节点保存日志就提交,那么后续新的领导者可能覆盖前面提交的日志,并提交,造成重复提交问题

因此提交日志规则:

1、日志存储在半数节点上

2、领导者必须看到半数节点山保存一条自己任期内的日志,这样新的领导者也有着要提交的日志

因此领导者在提交最新任期的日志时,也会顺带提交之前任期的日志

可是还有问题:如果最新的领导者(之前是3,现在是5)覆盖了之前的日志,此时没有新命令到来(日志无法到5),则无法提交之前日志,因此raft引入空日志,只有任期和索引,在更换领导者时立刻向自己本地追加空日志,不会阻塞查询(只有提交的日志才能返回)

清除不一样的日志

因为领导者必须保证跟随者的日志和自己的日志保持一致

因此对于少的日志会通过appendEntris补齐,对于多的日志会通过nextIndex[I]清除

nextIndex指向领导者的最后一条日志的下一条索引,appendEntris会包含前一条日志的任期和索引,当不一样时会递减,直到匹配

对于少的日志找到匹配的位置后补齐,对于多出的日志找到匹配的位置后删除后续日志然后补齐

处理旧领导者

由于每个RPC请求都会包含发送方的任期,因此旧的领导者即使收到客户端的请求,发送给其他节点,节点收到请求后发现对方任期太旧,然后拒绝请求,将最新任期发送给旧领导者,旧的领导者收到后更新自己的任期,然后将自己转为跟随者

客户端协议

客户端发送命令给任意一台服务器,服务器告知客户端领导者,然后客户端和领导者通信

由于可能导致命令重复执行,因此客户端发送请求时带上一个唯一的id,领导者在执行命令前先检查日志中id是否存在,不存在才会执行

存在则直接返回命令的响应

重复执行命令:领导者执行完命令返回之前下线,新的领导者又接收到命令

实现线性一致性读

1、领导者处理

当新的领导者的空日志提交后,领导者的提交Index至少和其他日志一样大

然后领导者将自己的提交Index 赋值给 readIndex

领导者收到读请求后,先发送心跳,确认自己是集群的领导者,然后等待状态机应用命令到readIndex

最后领导者执行读请求,返回给客户端

2、跟随者处理

跟随着先向领导者询问最新的readIndex,然后跟随着等待状态机应用命令,最后执行读请求,返回给客户端

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值