CAP原则
历史背景
- 所有的的计算任务都由一台计算机完成,数据的存储也由一台计算机完成
-
单节点计算
-
单点故障
-
性能瓶颈
-
IO瓶颈
-
内存
-
-
概念
Consistency:一致性
服务器端
从服务端来看,则是更新如何分布到整个系统,以保证数据最终一致。也就是N1节点和N2节点如何通信保数据的一致。
客户端:
- 从客户端来看,一致性主要指的是多并发访问时更新过的数据如何获取的问题。
- 系统在执行过某项操作后仍然处于一致的状态。在分布式系统中,更新操作执行成功后所有的用户都应该读取到最新值。
Availability:可用性
- 每一个操作总是能够在一定时间内返回结果。需要注意“一定时间”和“返回结果”。
- “一定时间”是指系统结果必须在给定时间内返回。
-
“ 返回结果 ” 是指系统返回操作成功或失败的结果。
Partition Tolerance:分区容错性
- 分区容错性指在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务。
- 这里可以理解为是否可以对数据进行分区。这是考虑到性能和可伸缩性。
推导
- 如果要求对数据进行分区了并且要求数据可用,就说明了必须节点之间必须进行通信,涉及到通信,就无法确保在有 限的时间内完成指定的任务
- 如果要求两个操作之间要完整的进行,因为涉及到通信,肯定存在某一个时刻只完成一部分的业务操作,在通信完成 的这一段时间内,数据就是不一致性的。
- 如果要求保证一致性,那么就必须在通信完成这一段时间内保护数据,使得任何访问这些数据的操作不可用。
取舍
- 满足CA舍弃P,也就是满足一致性和可用性,舍弃容错性。但是这也就意味着你的系统不是分布式的了,因为涉及分布式的想法就是把功能分开,部署到不同的机器上。
- 满足CP舍弃A,也就是满足一致性和容错性,舍弃可用性。如果你的系统允许有段时间的访问失效等问题,这个是可以满足的。就好比多个人并发买票,后台网络出现故障,你买的时候系统就崩溃了。
- 满足AP舍弃C,也就是满足可用性和容错性,舍弃一致性。这也就是意味着你的系统在并发访问的时候可能会出现数据不一致的情况。
- 在大型网站中,通常会选择强化分布式存储系统的可用性和伸缩性,在某种程度上放弃一致性
-
12306 ,京东抢购【AP 】
-
银行交易【 CP 】
-
数据的一致性
定义
- 一些分布式系统通过复制数据来提高系统的可靠性和容错性,并且将数据的不同的副本存放在不同的机器
- 在数据有多分副本的情况下,如果网络、服务器或者软件出现故障,会导致部分副本写入成功,部分副本写入失败。这就造成各个副本之间的数据不一致,数据内容冲突。
模型
强一致性
要求无论更新操作实在哪一个副本执行,之后所有的读操作都要能获得最新的数据。
弱一致性
最终一致性
- 是弱一致性的一种特例,保证用户最终能够读取到某操作对系统特定数据的更新。
-
从客户端来看,有可能暂时获取的不是最新的数据,但是最终还是能访问到最新的
- 从服务端来看,数据存储并复制到分布到整个系统超过半数的节点,以保证数据最终一致
Paxos算法
是什么
基于消息传递的分布式一致性算法
算法描述
Paxos 描述了这样一个场景:- 有一个叫做 Paxos 的小岛 (Island) 上面住了一批居民 (Islander) ;- 岛上面所有的事情由一些特殊的人决定,他们叫做议员 (Senator) ;- 议员的总数 (Senator Count) 是确定的,不能更改;- 岛上每次环境事务的变更都需要通过一个提议 (Proposal) ,每个提议都有一个编号 (PID) ,这个编号是一直增长的,不能倒退;- 每个提议都需要超过半数 ((Senator Count)/2 +1) 的议员同意才能生效 ( 少数服从多数 ) ;- 每个议员只会同意大于当前编号的提议,包括已生效的和未生效的;- 如果议员收到小于等于当前编号的提议,他会拒绝,并告知对方:你的提议已经有人提过了。这里的当前编号是每个议员在自己记事本上记录的编号,他会不断更新这个编号;- 整个议会不能保证所有议员记事本上的编号总是相同的;- 现在议会有一个目标:保证所有的议员对于提议都能达成一致的看法。现在议会开始运作,所有议员一开始记事本上面记录的编号都是 0 。有一个议员发了一个提议:将电费设定为 1 元 / 度。他首先看了一下记事本,嗯,当前提议编号是 0 ,那么我的这个提议的编号就是 1 ,于是他给所有议员发消息: 1 号提议,设定电费 1 元 / 度。其他议员收到消息以后查了一下记事本,哦,当前提议编号是 0 ,这个提议可接受,于是他记录下这个提议并回复:我接受你的 1 号提议,同时他在记事本上记录:当前提议编号为 1 。发起提议的议员收到了超过半数的回复,立即给所有人发通知: 1 号提议生效!收到的议员会修改他的记事本,将 1 好提议由记录改成正式的法令,当有人问他电费为多少时,他会查看法令并告诉对方: 1 元 / 度。再看冲突的解决:假设总共有三个议员 S1-S3 , S1 和 S2 同时发起了一个提议 :1 号提议,设定电费。 S1 想设为 1 元 / 度 , S2 想设为 2 元 / 度。结果 S3 先收到了 S1 的提议,于是他做了和前面同样的操作。紧接着他又收到了 S2 的提议,结果他一查记事本,咦,这个提议的编号小于等于我的当前编号 1 ,于是他拒绝了这个提议:对不起,这个提议先前提过了。于是 S2 的提议被拒绝, S1 正式发布了提议 : 1 号提议生效。 S2 向 S1 或者 S3 打听并更新了 1 号法令的内容,然后他可以选择继续发起 2 号提议。
Paxos推断
- 小岛(Island) 服务器集群
- 议员(Senator) 单台服务器
- 议员的总数(Senator Count)是确定的
- 提议(Proposal) 每一次对集群中的数据进行修改
- 每个提议都有一个编号(PID),这个编号是一直增长的
- 每个提议都需要超过半数((Senator Count)/2 +1)的议员同意才能生效
- 每个议员只会同意大于当前编号的提议
- 每个议员在自己记事本上面记录的编号,他不断更新这个编号
- 整个议会不能保证所有议员记事本上的编号总是相同的
- 议会有一个目标:保证所有的议员对于提议都能达成一致的看法。
- 前期投票(>1/2),后期广播(all)
-
Paxos 算法
-
数据的全量备份
-
算法延伸
如果 Paxos 岛上的议员人人平等,在某种情况下会由于提议的冲突而产生一个 “ 活锁 ” (所谓活锁我的理解是大家都没有死,都在动,但是一直解决不了冲突问题)。 Paxos 的作者在所有议员中设立一个总统,只有总统有权发出提议,如果议员有自己的提议,必须发给总统并由总统来提出。情况一:屁民甲 (Client) 到某个议员 (ZK Server) 那里询问 (Get) 某条法令的情况 (ZNode 的数据 ) ,议员毫不犹豫的拿出他的记事本 (local storage) ,查阅法令并告诉他结果,同时声明:我的数据不一定是最新的。你想要最新的数据?没问题,等着,等我找总统 Sync 一下再告诉你。情况二:屁民乙 (Client) 到某个议员 (ZK Server) 那里要求政府归还欠他的一万元钱,议员让他在办公室等着,自己将问题反映给了总统,总统询问所有议员的意见,多数议员表示欠屁民的钱一定要还,于是总统发表声明,从国库中拿出一万元还债,国库总资产由 100 万变成 99 万。屁民乙拿到钱回去了 (Client 函数返回 ) 。情况三:总统突然挂了,议员接二连三的发现联系不上总统,于是各自发表声明,推选新的总统,总统大选期间政府停业,拒绝屁民的请求。
作用
用于解决分布式系统中一致性问题
无主集群模式
人人都可以发送指令
-
投票人数有可能导致分区(分不同阵营),
-
6 个节点 33 对立
-
类似于以前党争
-
-
事务编号混乱,每个节点都有可能有自己的提议
-
提议的编号不能重复和小于
-
有主集群模式
- 只能有一个主发送指令,发送提议
- 单主会单点故障
- 重新选举,议员会把票投给数字编号和事务编号都大于自己的议员
- 数字编号(议员 ID,ZooKeeper 中叫 myid):为了快速选出总统
- 事务编号(会议 ID,ZooKeeper 中叫 ZXID):为了确定谁的数据是最全的
- 选主过程:先比较 ZXID,如果 ZXID 相同再比较 myid
- 如果存在多个主就会脑裂
- 选主过程:先比较 ZXID,如果 ZXID 相同再比较 myid
- 如果存在多个主就会脑裂
- 节点越多业务能力越强,但是选举速度也会越慢
- 减少参与选举和投票的人数(例如 ZooKeeper 的 Observer)
Raft算法
作用
用于一个管理日志一致性的协议
角色分配
Leader
负责Client交互和log复制,同一时刻系统中最多存在1个。
Follower
负责Client交互和log复制,同一时刻系统中最多存在1个。
Candidate
一种临时的角色,只存在于leader的选举阶段,某个节点想要变成leader,那么就发起投票请求,同时自己变成candidate
算法流程
Term任期
任期高的成为新的Leader
RPC远程过程调用
作用:节点与节点之间的通信协议
作用:节点与节点之间的通信协议
AppendEntries RPC:领导人发起的一种心跳机制,复制日志也在该命令中完成
InstallSnapshot RPC: 领导者使用该RPC来发送快照给太落后的追随者
日志复制
- 主要用于保证节点的一致性,这阶段所做的操作也是为了保证一致性与高可用性。
- 当Leader选举出来后便开始负责客户端的请求,所有事务(更新操作)请求都必须先经过Leader处理
- 日志复制(Log Replication)就是为了保证执行相同的操作序列所做的工作。
- 在Raft中当接收到客户端的日志(事务请求)后先把该日志追加到本地的Log中 ,然后通过heartbeat把该Entry同步给其他Follower,Follower接收到日志后记录日志然后向Leader发送ACK
- 当Leader收到大多数(n/2+1)Follower的ACK信息后将该日志设置为已提交并追加到本地磁盘中
- 通知客户端并在下个heartbeat中Leader将通知所有的Follower将该日志存储在自己的本地磁盘中。
流程
领导者接收到客户端的事务请求,将请求信息追加到本地的Log中,通过心跳将该事务信息发送给跟随者,跟随者接收到领导者的日志信息后将日志信息记录,然后向领导者发送响应
ZAB协议
作用
为分布式协调服务 Zookeeper 专门设计的一种支持 崩溃恢复 和 原子广播 协议,基于该协议,Zookeeper 实现了一种 主备模式 的系统架构来保持集群中各个副本之间数据一致性。
原理
-
发现
- zookeeper必须选出一个leader进程,同时leader会维护一个follower可用列表。将来客户端可follower中的节点进行通信
-
同步
- leader要负责将本身的数据与follower完成同步,做到多副本存储。这样也是体现了CAP中CPfollower将队列中未处理完的请求消费完成后,写入本地事物日志中。
- 广播
- leader可以接受客户端新的proposal请求,将新的proposal请求广播给所有的follower。
协议内容
-
崩溃恢复
-
原子广播
角色分配
- 小岛——ZK Server Cluster
- 总统——ZK Server Leader
- 集群中所有修改数据的指令必须由总统发出
- 总统是由议员投票产生的(无主-->有主)
- 选举条件
- 首先按照事务zxid进行排序
- 如果事务相同按照myid排序
- 议员(Senator)——ZK Server Learner
- 接受客户端请求
- 查询直接返回结果(有可能数据不一致)
- 写入数据,先将数据写入到当前server
- 发送消息给总统,总统将修改数据的命令发送给其他server
- 其他server接受命令后开始修改数据,修改完成后给总统返回成功的消
- 当总统发现超过半数的人都修改成功,就认为修改成功了
- 并将信息传递给接受请求的zkServer,zkServer将消息返回给客户端,说明数据更新完成
- Follower
- 拥有选举权,拥有投票权
- 接受客户端的访问
- 如果客户端执行写请求,只是将请求转发给Leader
- Observer
- 只可以为客户端提供数据的查询和访问
- 如果客户端执行写请求,只是将请求转发给Leader
- 提议(Proposal)——ZNode Change
- 客户端的提议会被封装成一个节点挂载到一个Zookeeper维护的目录树上面
- 我们可以对数据进行访问(绝对路径)
- 数据量不能超过1M
- 提议编号(PID)——Zxid
- 会按照数字序列递增,不会减少不会重复
- 正式法令——所有ZNode及其数据
- 超过半数的服务器更新这个数据,就说明数据已经是正式的了
- 屁民--Client
- 发送请求(查询请求,修改请求)
存储模型
-
存储结构
-
zookeeper是一个树状结构,维护一个小型的数据节点znode
-
数据以keyvalue的方式存在,目录是数据的key
-
所有的数据访问都必须以绝对路径的方式呈现
-
-
节点分类
-
持久化节点
-
普通持久化节点
-
顺序节点
-
临时节点
-
普通
-
顺序
-
-
-