ZK
说明
本篇文章存在的主要意义就是帮助我加深记忆顺利拿offer的,只符合我的阅读习惯,如有朋友搜到,仅做参考。
1. ZK的数据模型:节点的特性与应用
1.1 节点的类型
zookeeper维护一个具有层次关系的数据结构,它非常类似于一个标准的文件系统,且只能以绝对路径访问,包括以下三种类型。
临时:随着客户端会话的断开而断开
持久:不会随着创建的客户端的断开而删除,除非显式的调用delete
有序:在节点上加上了序号,可以清晰的看到节点的创建顺序
1.2 节点的状态结构
利用命令“stat 节点”查看,节点包含的信息如下所示
1.3 zk实现的锁
** 悲观锁:通过创建一个节点的lock来实现,坏处就是会锁住这个资源,效率低下
** 乐观锁:通过节点的版本号实现,利用CAS原理去更新节点的信息
2. 发布订阅模式:如何使用watch机制实现分布式通知
2.1 ZK机制的实现
通过向ZK客户端构造函数传递Watch实现
还可以通过getData、exists、getChildren实现
2.2 客户端Watch 注册实现过程
标记该会话是一个带有 Watch 事件的请求
将 Watch 事件存储到 ZKWatchManager
2.3服务端 Watch 注册实现过程
解析收到的请求是否带有 Watch 注册事件
将对应的 Watch 事件存储到 WatchManager
2.4 服务端Watch时间的触发过程
会调用WatchManager.triggerWatch方法触发事件变更,并删除watch triggerWatch 函数内部,封装了一个具有会话状态、事件类型、数据节点 3 种属性的 WatchedEvent 对象。之后查询该节点注册的 Watch 事件,如果为空说明该节点没有注册过 Watch 事件。如果存在 Watch 事件则添加到定义的 Wathcers 集合中,并在 WatchManager 管理中删除。最后,通过调用 process 方法向客户端发送通知。
2.5 客户端回调的过程
通过SendThread.readResponse() 方法来统一处理服务端的相应,处理完后并删除watch
所以综上所述,watch具有一次性,如果要继续对某一个节点进行继续监听,需要在客户端的回调中,重新创建监听
3. ACL权限控制:如何避免未经授权的访问
一个 ACL 权限设置通常可以分为 3 部分,分别是:权限模式(Scheme)、授权对象(ID)、权限信息(Permission)。最终组成一条例如“scheme🆔permission”格式的 ACL 请求信息。
3.1权限模式:Scheme
用来设置 ZooKeeper 服务器进行权限验证的方式
包括范围验证(IP)和口令验证(用户名、密码)
3.2 授权对象(ID)
IP 方式,使用的授权对象可以是一个 IP 地址或 IP 地址段
Digest 或 Super 方式,则对应于一个用户名
如果是 World 模式,是授权系统中所有的用户
3.3 权限,ZK中定义好的权限有5种
数据节点(create)创建权限,授予权限的对象可以在数据节点下创建子节点;
数据节点(wirte)更新权限,授予权限的对象可以更新该数据节点;
数据节点(read)读取权限,授予权限的对象可以读取该节点的内容以及子节点的信息;
数据节点(delete)删除权限,授予权限的对象可以删除该数据节点的子节点;
数据节点(admin)管理者权限,授予权限的对象可以对该数据节点体进行 ACL 权限设置。
总结:每个节点都有维护自身的 ACL 权限数据,即使是该节点的子节点也是有自己的 ACL 权限而不是直接继承其父节点的权限。
4. ZAB协议
4.1基本概念
-
集群节点的角色
Leader:同一时间集群总只允许有一个Leader,提供对客户端的读写功能,负责将数据同步至各个节点;
Follower:提供对客户端读功能,写请求则转发给Leader处理,当Leader崩溃失联之后参与Leader选举;
Observer:与Follower不同的是但不参与Leader选举 -
服务节点的状态
Leading:当前节点是 Leader,负责协调事务
Following:当前节点是跟随者,服从 Leader 节点的命令
Election/Looking:节点处于选举状态,正在寻找 Leader
Observing:和leadering的状态很像,但是其不参与选举 -
Zab状态
election: 集群进入选举状态,此过程会选出一个节点作为leader角色;
discovery:连接上leader,响应leader心跳,并且检测leader的角色是否更改,通过此步骤之后选举出的leader才能执行真正职务;
synchronization:整个集群都确认leader之后,将会把leader的数据同步到各个节点,保证整个集群的数据一致性;
broadcast:过渡到广播状态,集群开始对外提供服务。 -
ZXID
ZXID又称为事务的ID,zookeeper每次状态的变化都会接收一个ZXID(ZooKeeper事务id),ZXID是一个64位的数字,由Leader统一分配,全局唯一,不断递增。 -
高32位
代表了leader周期的epoch编号, epoch 编号可以理解为当前集群所处的年代,或者周期。每次Leader变更之后都会在 epoch 的基础上加1,这样旧的 Leader 崩溃恢复之后,其他Follower 也不会听它的了,因为 Follower 只服从epoch最高的 Leader 命令。 -
低32位
一个简单的单增计数器,针对客户端每一个事务请求,Leader 在产生新的 Proposal 事务时,都会对该计数器加1
每当选举产生一个新的leader时,便会取出本地日志中最大proposal的zxid,并解析出高32位的epoch,对其进行加1,作为新的epoch值,并将低32位的数字归零,又0开始重新生成zxid
4.2 ZAB协议
4.2.1 什么是ZAB协议
Zab协议是为分布式协调服务Zookeeper专门设计的一种支持崩溃恢复的原子广播协议,是Zookeeper保证数据一致性的核心算法。基于该协议,zk实现了一种主备模型(即Leader和Follower模型)的系统架构来保证集群中各个副本之间数据的一致性。
顺序一致性:从一个客户端发起的事务请求,最终将严格地按照其发起的顺序被应用到zookeeper中。
原子性:所有事务请求处理的结果在整个集群中所有机器上的应用情况是一致的,也就是说,要么整个集群所有的机器都成功应用了某一个事务,要么就都没有应用。
可靠性:一旦服务器成功地应用了某一个事务,并完成了对客户端的响应,那么该事务所引起的服务器状态将会一致保留下来,除非有一个事务对其更改。
单一视图:无论客户端连接的是哪一个zookeeper服务器,所看到的服务器端数据模型都是一致的。
实时性:一旦某个事务被应用成功,那么客户端能够立刻从服务器上获取变更后的新数据。
4.2.2 ZAB协议的作用
4.2.2.1 Zab协议要求每个leader都要经历三个阶段
(1)发现:要求zookeeper集群必须选举出一个 Leader 进程,同时 Leader 会维护一个 Follower 可用客户端列表。将来客户端可以和这些 Follower节点进行通信。
(2)同步:Leader 要负责将本身的数据与 Follower 完成同步,做到多副本存储。这样也是提现了CAP中的高可用和分区容错。Follower将队列中未处理完的请求消费完成后,写入本地事务日志中。
(3)广播:Leader 可以接受客户端新的事务Proposal请求,将新的Proposal请求广播给所有的 Follower。
4.2.2.2 ZAB协议的作用
(1)使用一个单一的主进程(Leader)来接收并处理客户端的事务请求(也就是写请求),并采用了Zab的原子广播协议,将服务器数据的状态变更以事务proposal (事务提议)的形式广播到所有的副本(Follower)进程上去。
(2)保证一个全局的变更序列被顺序引用。为了保证这一点,Zab要保证同一个Leader发起的事务要按顺序被apply,同时还要保证只有先前Leader的事务被apply之后,新选举出来的Leader才能再次发起事务。
(3)当主进程出现异常的时候,整个zk集群依旧能正常工作。
4.2.3 ZAB协议的内容
ZAB协议包括两个阶段,分别为崩溃恢复和消息广播
4.2.3.1 崩溃恢复
(1)什么时候进行崩溃恢复---选举的时机
服务器启动的时候
当leader 服务器出现网络中断,崩溃或者重启的情况
当集群中已经不存在过半的服务器与Leader服务器保持正常通信。
(2)崩溃恢复阶段会做什么
崩溃恢复阶段主要包括两个状态,分别是Leader选举和数据同步
- a. Leader选举
基本概念
logicalclock(electionEpoch) 本地选举周期,每次投票都会自增
epoch(peerEpoch) 选举周期,每次选举最终确定完leader结束选举流程时会自增(真正zxid的前32位)
serverId 服务器ID,即sid,数值越大,权重越大
zxid 最新的是事务ID,越大说明数值越新,真正ZID的后32位
选举的过程
-
(1)先投自己为leader,投票信息为(sid,zid)
-
(2)将自己的投票信息广播到其他的节点
-
(3)投票信息的处理
- 判断该投票是否是本轮投票,若不是本轮的投票则投票信息失败,选择最大的epoch
- 若epoch相同,则选择zxid最大的
- 若zxid相同,则选择sid最大的
-
(4)根据上述的结果重新修改自己的投票
-
(5)当任一个节点的得票数超过一半的时候,该节点会修改自己的状态为leading,其他的节点修改自己的状态为Following
注意:只有状态在following的时候才会参加选举 -
b.数据同步
(1)完成 Leader 选举后(新的 Leader 具有最高的zxid),在正式开始工作之前(接收事务请求,然后提出新的 Proposal),Leader 服务器会首先确认事务日志中的所有的 Proposal 是否已经被集群中过半的服务器 Commit
(2)Leader 服务器需要确保所有的 Follower 服务器能够接收到每一条事务的 Proposal ,并且能将所有已经提交的事务 Proposal 应用到内存数据中。等到 Follower 将所有尚未同步的事务 Proposal 都从 Leader 服务器上同步过来并且应用到内存数据中以后,Leader 才会把该 Follower 加入到真正可用的 Follower 列表中 -
c.备注
成为新的leader的服务器需要满足以下的条件
(1)不能包含未提交的 Proposal,即如果是上一个leader,收到了超过半数服务器的ack,但是事务没有commit,这个服务器就不能成为新的leader
(2)新选举的 Leader 节点中含有最大的 zxid,即这个新的节点中的事务是最新的
已经处理过的事务不能丢
新的leader拥有最新的事务编号ZXID,会将已经处理过的事务同步到所有的副本
没有被提交的proposal需要丢弃
当一个包含了上一个 Leader 周期中尚未提交过的事务 Proposal 的服务器启动时,当这台机器加入集群中,以 Follower 角色连上 Leader 服务器后,Leader 服务器会根据自己服务器上最后提交的 Proposal 来和 Follower 服务器的 Proposal 进行比对,比对的结果肯定是 Leader 要求 Follower 进行一个回退操作,回退到一个确实已经被集群中过半机器 Commit 的最新 Proposal。
4.2.3.2 消息广播
(1)客户端发起一个写操作请求。
(2)Leader 服务器将客户端的请求转化为事务 Proposal 提案,同时为每个 Proposal 分配一个全局的ID,即zxid。
(3)Leader 服务器为每个 Follower 服务器分配一个单独的队列,然后将需要广播的 Proposal 依次放到队列中取,并且根据 FIFO 策略进行消息发送。
(4)Follower 接收到 Proposal 后,会首先将其以事务日志的方式写入本地磁盘中,写入成功后向 Leader 反馈一个 Ack 响应消息。
(5)Leader 接收到超过半数以上 Follower 的 Ack 响应消息后,即认为消息发送成功,可以发送 commit 消息。
(6)Leader 向所有 Follower 广播 commit 消息,同时自身也会完成事务提交。Follower 接收到 commit 消息后,会将上一条事务提交。
zookeeper 采用 Zab 协议的核心,就是只要有一台服务器提交了 Proposal,就要确保所有的服务器最终都能正确提交 Proposal。这也是 CAP/BASE 实现最终一致性的一个体现。
备注:Leader 服务器与每一个 Follower 服务器之间都维护了一个单独的 FIFO 消息队列进行收发消息,使用队列消息可以做到异步解耦。 Leader 和 Follower 之间只需要往队列中发消息即可。如果使用同步的方式会引起阻塞,性能要下降很多。
5. 二阶段提交和三阶段提交
5.1 什么是数据的一致性
在ZK中,为了保证数据的高可用,数据被备份为多个副本,由于网络或者软件等等原因,会造成副本之间数据的不一致性
5.2 CAP原理
Consistency:一致性,在分布式系统中,更新操作执行成功后,所有的用户都应该读取到最新的值
Availability:可用性,每一个操作总能在一定的时间内返回结果。
Partition Tolerance:分区容忍性,是否可以对数据进行分区
5.3 二阶段提交
5.3.1 二阶段提交原理
二阶段提交协议包括两个部分,一个是请求阶段,一个是提交阶段。
包括两种角色,一个是协调者,一个是参与者。
协调者在请求阶段,通知所有的参与者准备提交或者取消事务,然后进入表决过程,参与者告诉协调者自己的决定。根据上一阶段的决策,在提交阶段,协调者会根据上一阶段的投票,当且仅当所有的参与者同意提交,决定提交事务。否则就通知所有的参与者取消事务。
5.3.2 二阶段提交缺点
同步阻塞:执行过程中,所有的参与者都是事务阻塞型的
单点故障:由于协调者的重要性,一旦协调者发生故障,则参与者也会一直阻塞下去,特别是第二阶段,协调者发生故障,参与者处于事务资源锁定的状态,无法完成事务的操作(如果是协调者宕机了,则可以重新选择一个协调者,但是故障的情况无法处理)
数据不一致:二阶段提交过程中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了commit请求。(这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据部一致性的现象。)
5.4三阶段提交
5.4.1三阶段提交的原理
分为Cancommit、Precommit、Docommit三个阶段
- CanCommit阶段
3PC的CanCommit阶段其实和2PC的准备阶段很像。 协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。 - PreCommit阶段
Coordinator根据Cohort的反应情况来决定是否可以继续事务的PreCommit操作
分为两个情况:
1.如果所有的参与者反馈的都是yes,那么进入prepare阶段
2.假设有一个参与者超时没反馈或者有一个反馈了NO,那么中断事务的提交 - Docommit
进行真正的事务提交,也可以分为两个阶段
执行提交
1.协调者像参与者发送事务
2.参与者提交事务,执行成功后释放资源
3.事务提交完成后,像协调者发送ack响应
4.协调者在接受到ACK响应后,完成事务
中断事务
协调者没有收到参与者的ack信号,或者超时了没有收到,那么就会执行中断事务的操作
5.4.2 三阶段提交的缺点
如果进入PreCommit后,Coordinator发出的是abort请求,假设只有一个Cohort收到并进行了abort操作,而其他对于系统状态未知的Cohort会根据3PC选择继续Commit,此时系统状态发生不一致性。
5.4.3和二阶段的不同点
对于协调者(Coordinator)和参与者(Cohort)都设置了超时机制(在2PC中,只有协调者拥有超时机制,即如果在一定时间内没有收到cohort的消息则默认失败)。在2PC的准备阶段和提交阶段之间,插入预提交阶段,使3PC拥有CanCommit、PreCommit、DoCommit三个阶段。PreCommit是一个缓冲,保证了在最后提交阶段之前各参与节点的状态是一致的。
5.5 paxos
分布式一致性协议
角色:提议者、接受者、学习者
特点:在所有被提出的提案中,只有一个会被选定。
如果没有提案被选出,就不会有选定的提案。
当一个提案被选定后,所有的节点进程都可以获取到被选定的提案信息。
一旦 “接受者” 接受了提议,就不能再接受其他提议内容。
参考网址: https://blog.csdn.net/qq_14855971/article/details/105136999