CAP理论
- Consistency 一致性
- Availability 可用性
- Partition Tolerance 分区容错性
- 上述三个特点构成不可达成三角,最多只能满足其中的两个,如满足一致性和分区容错性最大可能提高可用性 或者 满足分区容错性和可用性最大可能提高一致性
强一致性和弱一致性
-
强一致性
- 任何时刻,所有节点数据一致
- 任何一次读取操作都是最新的数据
- 全局时钟下的顺序是一致的
- 模型 Paxos Raft(multi-paxos) ZAB (multi-paxos)
-
弱一致性
-
最终一致性,不保证数据的提交立刻同步到集群中所有节点,但随着时间推移最终状态是一致的
-
模型 DNS系统 Gossip协议
etcd 使用了Raft协议 Zookeeper使用了ZAB
Canssandra使用了Gossip协议
BASE理论
- Basically Available 基本可用
- Soft State 软状态
- Eventually Consistent 最终一致性
- 当分布式系统无法做到强一致性,可以使用一些手段实现弱一致性,但某一个时间点可能数据是不一致的,但经过一段时间之后最终会达到一致性.在当个时间点上看可能是不一致性的,但从整体上看数据最终是一致的.比如Cassandra就是使用了弱一致性协议Gossip协议来保证数据的最终一致性,从而提高分布式系统的可用性
Basic-Paxos
角色分类
- Proposer 提案者: 可以有多个,用于拟定上报一个提案Proposal标记提案编号为N,内容记为Value 类似现实中法官的角色
- Acceptor 接收者: 用于接收Proposer提出的提案,并投票决定采用哪一个提案 类似现实中的陪审团投票决定某一个提案是否有效
- Learner 学习者: 在最终决定采用某一个提案之后进行记录. 类似现实中的书记员
- Client 客户端: 用于向Proposer提出一个提案 类似中现实中的民众
规则
- Acceptor必须接受第一个提案
- Acceptor只接受最新的提案,比如接受到一个提案编号为N,会丢弃N-1 之前的所有提案
- 必须当超过半数的Acceptor同意之后提案才会通过
步骤
- prepare阶段
- Proposer提出提案[N1,V1],发送给所有Acceptor
- Acceptor接受到提案之后判断当前提案号N1是不是最新的,如果不是直接丢弃
- 比如Acceptor已经恢复过N2提案 N2>N1 此时会忽略N1的这次请求
- 否则回复Proposer 接受这次提案
- accept阶段
- 当Proposer接受到Acceptor回复情况分如下几种
- Acceptor超过半数回复的是OK,则Proposer发出accept请求 内容为提案<N1,V1>
- 如果没有超过半数的回复,Proposer尝试将提案号+1继续执行 <N1+1,V1>
- 当Proposer接受到Acceptor回复情况分如下几种
- learn阶段
- Leaner记录通过的提案
故障情况
- Proposer故障 从集群中在选出一个Proposer即可
- Acceptor故障 只要表决的时候能达到多数派即可
存在问题
- 活锁 如果系统中有多个Proposer的时候,Proposer1先向Acceptor发出提案[1,v1],上一个提案还没有达到多数派表态的时候,Proposer2下一个提案[2,v2]又来了,此时提案版本号2>1,导致所有Acceptor丢弃了之前的提案,Proposer1发现自己的提案被忽略又将自己的提案版本号+1继续提[3,V1],又把Proposer2的提案顶掉了.周而复始,导致任何提案都无法通过
Multi Paxos
根据Basic Paxos的改进 整个系统在一个时刻只有一个Proposer能发起提案称为Leader,减少了大量的prepare请求.
在集群中没有leader的情况下,所有Proposer角色可以发起Leader选举投票,选出集群中的leader,由集群的leader发起提案请求.当集群leader宕机之后,会重新选取集群的leader
multi-paxos的leader状态的流程图变成了 省略了prepare阶段的过程,整个集群只选取了一个Proposer作为Leader来在集群中发起提案
- leader直接告诉acceptor,准备提交版本号为v+1的协议
- 收到大部分acceptor的回复之后,acceptor直接回复client协议成功写入
- Accept的过程类似与prepare的过程,在没有获得半数以上同意的时候,协议在超时之后会返回失败,此时v+1的版本号协议没有通过,下个请求仍是使用v+1的版本号
Client Leader Acceptor Learner
| | | | | | | --- Following Requests ---
X-------->| | | | | | Request
| X--------->|->|->| | | Accept!(N,I+1,W)(prepare)
| |<---------X--X--X------>|->| Accepted(N,I+1,W)(prepared)
|<---------------------------------X--X Response
| | | | | | |
Raft
- Raft是用来管理分布式日志复制一致性的算法
- Raft是multi-paxos的一种简化版本
- Raft提供了一种一致性场景,客户端调用put(x)=y,一旦写入成功,则x的值在raft集群中存在能提供服务的情况下,一定会返回get(x)=y, 此时不保证raft集群中的每一台机器上都是get(x)=y
Raft角色
- leader 集群主节点 整个集群只有一个leader节点 类似paxos中的proposer,会定时给follower发送心跳
- follower 集群从节点, 与leader建立通信,参与提案的投票,类似paxos中的acceptor.每个follower有超时机制,当一定时间没有收到心跳,集群进入选举状态.每个follower的超时时间是随机的,避免了如果leader宕机所有follower同时都去竞选
- candidate 候选主节点 当follower与leader感知断开之后,candidate可以参与竞选leader
leader选举
- 当集群初始化,或者leader宕机的情况下,需要选出新的leader.
- 此时集群进入新的任期term,如果选取成功新的leader开始工作,否则视为任期终止,开始下一轮任期选举
- 选取是candidate发起,当leader宕机之后,follower会将自己的任期编号term+1,宣告参与竞选,并投自己一票,并向其他服务器拉票.每个服务器一个任期只能投一票,固定投给最早拉票的服务器.
- 如果candidate收到了其他服务器的拉票行为,而拉票服务器的任期编号大于自己的任期编号,则自动落选成为follower,并投拉票者一票.如果有candidate收到了超过半数选票成为新leader.如果超时没有选出新leader,此时任期自动终止,发起重新一次选举
- Raft每个服务器的超时期限是随机的,这降低伺服务同时竞选的几率,也降低因两个竞选人得票都不过半而选举失败的几率
记录复写
- leader负责集群的记录复写,负责接受client的请求.每次接受到client的指令,leader中追加一个新的entry,并将指令发给所有的follower,如果follower没有回应,leader会一直发送,直到每个follower都成功写入
- 当leader收到超过半数的follower成功写入的回复之后,将指令视为已存储committed.当follower发现指令办成已存储的时候,会执行在其状态机上执行该指令
- 当leader宕机之后,leader的某一些指令可能还没同步到整个集群,此时集群的记录会不一致.在选取中新的leader之后需要重新让集群变成一致性. 方法是对每个follower进行记录对比,找出两者一致的最后一条指令,删除follower之后的指令,把自己之后的指令拷贝给follower.此阶段完成之后,整个集群又变成一致
安全性
- leader安全性 整个集群一个任期term只有一个leader
- leader的附加性 leader只会把指令附加到记录尾部,不会改写或删除已经存在的指令
- 记录符合性 如果某一条指令在两个记录中的任期和指令序号一致,则保证序号较小的指令也完全一样
- leader完整性: 如果某一个指令在某一个任期存储成功,则保证存在与leader该任期的记录中
- 状态机安全性 如果某服务器在其状态上运行某指令,其他服务器保证不会在同一个上运行不同的指令
异常情况
- follower宕机 发送端发送指令和拉票信息没有回应而失败,此时发送端会持续重发.当follower恢复重新加入集群之后会收到这些消息,follower重新回应,如果此时指令已经写入不会重复写入,如果没有写入则写入保证集群一致性
- leader宕机 每个已存储的指令已经写入过半的服务器,此时选举时会记录最完成的服务器胜选.其中一个原因是raft的candidate会揭露自己记录的最新一笔信息.如果服务器自己的记录比较新,就不会投票给其他的candidate
ZAB
Zab全称Zookeeper Atomic Broadcast.是一种paxos的简单实现.zk主要依赖了Zab协议来完成数据的一致性,基于ZAB协议ZK实现了一种主备模型的系统架构保证这个集群中的节点的一致性.集群中一个leader负责处理外部的写请求,然后leader将数据同步给其他follower
与raft类似不同之处在于zab用epoch和count来表示唯一值,raft对应term任期和index
- 客户端发起一个写操作请求Leader服务器将客户端的request请求转化为事务proposal提案,同时为每个proposal分配一个全局唯一的ID,即ZXID。
- leader服务器与每个follower之间都有一个队列,leader将消息发送到该队列
- follower机器从队列中取出消息处理完(写入本地事物日志中)毕后,向leader服务器发送ACK确认。
- leader服务器收到半数以上的follower的ACK后,即认为可以发送commit
- leader向所有的follower服务器发送commit消息。