ZooKeeper整理精华
2021-08-15 15:47:29 0 举报
AI智能生成
ZooKeeper整理精华
作者其他创作
大纲/内容
基础篇
基础知识
介绍
是一个开源的分布式协调框架,它的定位是为分布式应用提供一致性服务
ZooKeeper = 文件系统 + 监听通知机制
数据模型
持久节点
客户端与zookeeper断开连接后,该节点依旧存在
临时节点
当跟客户端会话失效时则会删除该节点
有序节点
有序节点并不算是一种单独种类的节点,而是在之前提到的持久节点和临时节点特性的基础上,增加了一个节点有序的性质
ACL 权限控制
权限模式(Scheme)、授权对象(ID)、权限信息(Permission)
组成一条例如“scheme:id:permission”格式的 ACL 请求信息
权限模式:Scheme
范围验证:ZooKeeper 可以针对一个 IP 或者一段 IP 地址授予某种权限
口令验证:理解为用户名密码的方式
Watch 监控
客户端可以在服务端注册一个watcher监听,当服务端的一些指定事件触发watcher, 那么服务端会向客户端发送事件通知
注册的watcher监听是一次性的
EventType
NodeCreated、NodeChildrenChanged、NodeDataChanged、 NodeDeleted
添加事件方式
ZooKeeper 客户端也可以通过 getData、exists 和 getChildren 三个接口来向 ZooKeeper 服务器注册 Watcher
getData(String path, Watcher watcher, Stat stat)
触发条件(EventType)
NodeCreated
NodeDeleted
NodeDataChanged
NodeChildrenChanged
Watcher机制
其结构很像设计模式中的”观察者模式“,一个对象或者数据节点可能会被多个客户端监控,当对应事件被触发时,会通知这些对象或客户端
客户端 Watch 注册实现过程
标记该会话是一个带有 Watch 事件的请求
将 Watch 事件存储到 ZKWatchManager
服务端 Watch 注册实现过程
解析收到的请求是否带有 Watch 注册事件
将对应的 Watch 事件存储到 WatchManager
服务端 Watch 事件的触发过程
dataWatches.triggerWatch(path, EventType.NodeDataChanged);
|—封装一个具有会话状态、事件类型、数据节点 3 种属性的 WatchedEvent 对象
调用 process 方法向客户端发送通知
客户端回调的处理过程
客户端使用 SendThread.readResponse() 方法来统一处理服务端的相应
反序列化服务器发送请求头信息,判断相属性字段 xid 的值为 -1,表示该请求响应为通知类型
在处理通知类型时,首先将己收到的字节流反序列化转换成 WatcherEvent 对象
调用 eventThread.queueEvent( )方法将接收到的事件交给 EventThread 线程进行处理
|—第 1 步按照通知的事件类型,从 ZKWatchManager 中查询注册过的客户端 Watch 信息
|—调用 processEvent(event) 方法来最终执行实现了 Watcher 接口的 process()方法
提供功能
数据发布/订阅
先在节点中存储数据(如数据库配置项、第三方接口、服务地址等),当数据放生变更时通知客户端
分布式锁
1.保持独占
核心思想:在zk中有一个唯一的临时节点,只有拿到节点的才可以操作数据,没拿到的线程就需要等待。
缺点:可能引发羊群效应,第一个用完后瞬间有999个同时并发的线程向zk请求获得锁。
2.控制时序
主要是避免了羊群效应,临时节点已经预先存在,所有想要获得锁的线程在它下面创建临时顺序编号目录节点,编号最小的获得锁,用完删除,后面的依次排队获取。
负载均衡
1.多个服务注册 2.客户端获取中间件地址集合 3.从集合中随机选一个服务执行任务
ZooKeeper负载均衡和Nginx负载均衡区别
序列化
什么是序列化,为啥要进行序列化
Java中如何进行序列化
zk的序列化方案
使用 Jute 实现序列化
首先需要该类实现 Record 接口的 serilize 和 deserialize 方法,这两个方法分别是序列化和反序列化方法
工具类
OutputArchive
BinaryOutputArchive
InputArchive
BinaryInputArchive
Jute 可以通过 Binary 、 Csv 、Xml 等方式进行序列化操作
网络通信协议
ZooKeeper 则是在 TCP/IP 协议的基础上实现了自己特有的通信协议格式。
请求协议
客户端请求头底层解析
在 ZooKeeper 中请求头是通过 RequestHeader 类实现的。首先 RequestHeader 类实现了 Record 接口,用于之后在网络传输中进行序列化操作。
RequestHeader 类中只有两个属性字段分别是 xid 和 type,分别代表客户端序号用于记录客户端请求的发起顺序以及请求操作的类型。
客户端请求体底层解析
协议的请求体包括了协议处理逻辑的全部内容
在 ZooKeeper 的内部实现中,根据不同的请求操作类型,会采用不同的结构封装请求体
举例
会话创建
节点查询
节点更新
响应协议
服务端请求头解析
服务端请求体解析
进阶篇
单机模式:服务器如何从初始化到对外提供服务
程序启动
QuorumPeerMain
main.initializeAndRun(args);
判断服务启动方式是集群模式还是单机模式
zoo.cfg 配置文件解析
可以配置数据目录、端口号等信息
创建历史文件清理器
集群模式:服务器如何从初始化到对外提供服务
runFromConfig 函数完成之后的集群模式的初始化工作。
Leader 服务器启动过程
zoo.cfg 配置文件中的参数,选择参数文件中规定的 Leader 选举算法
创建用来选举 Leader 节点的工具类 QuorumCnxManager
根据服务器自身的服务器 ID(SID)、最新的 ZXID、和当前的服务器 epoch (currentEpoch)这三个参数来生成一个选举标准
Follow 服务器启动过程
和 Leader 节点进行数据同步和交互
LearnerCnxAcceptor
LearnerHandler
ClientCnxn:客户端核心工作类工作原理解析
客户端核心类
角色
调度者
负载均衡服务器就是一种调度者的实现方式
Leader
处理读写请求,处理完写请求会广播事务,当过半节点写入成功,则会提交事务
管理协调集群中的 Follow 角色服务器
在 ZooKeeper 集群中,Leader 服务器主要负责处理事物性的请求,而在接收到一个客户端的事务性请求操作时,Leader 服务器会先向集群中的各个机器针对该条会话发起投票询问。
当一个事务性的请求导致服务器上的数据发生改变时,ZooKeeper 只要保证集群上的多数机器的数据都正确变更了,就可以保证系统数据的一致性。
Follow
只能处理读请求,当收到写请求会转发给leader处理。参与选举
Observer
负责处理来自客户端的诸如查询数据节点等非事务性的会话请求操作
Observer 不参与 Leader 服务器的选举工作,也不会被选举为 Leader 服务器
Learner
进行 Follower、Observer 服务器与 Leader 服务器的数据同步
事务性会话请求的转发以及 Proposal 提议投票等功能
高级篇
Leader 选举
一个 ZooKeeper 服务要想满足集群方式运行,至少需要三台服务器
集群启动
服务器启动--》网络检查(检查服务器间是否可以通信)--》寻找集群中的 Leader 服务器并进行数据同步等操作
发起通票:发送的服务器的 myid(服务器标识符)和 ZXID (集群投票信息标识符)等选票信息字段都指向本机服务器
接收投票:在接收到网络中的投票信息后,服务器内部首先会判断该条投票信息的有效性。检查该条投票信息的时效性,是否是本轮最新的投票,并检查该条投票信息是否是处于 LOOKING 状态的服务器发出的。
统计投票:主要进行对比的内容是 ZXID,ZXID 数值比较大的投票信息优先作为 Leader 服务器。如果每个投票信息中的 ZXID 相同,就会接着比对投票信息中的 myid 信息字段,选举出 myid 较大的服务器作为 Leader 服务器。
统计集群中服务器的投票结果,判断是否有过半数的机器投出一样的信息。如果存在过半数投票信息指向的服务器,那么该台服务器就被选举为 Leader 服务器。
当 ZooKeeper 集群选举出 Leader 服务器后,ZooKeeper 集群中的服务器就开始更新自己的角色信息,除被选举成 Leader 的服务器之外,其他集群中的服务器角色变更为 Following。
QuorumCnxManager
RecvWorker :接收消息
SendWorker :发送消息
3.4.0后的Zookeeper的版本只保留了TCP版本的FastLeaderElection选举算法
运行时选举
变更状态:当 Leader 服务器崩溃后 ,ZooKeeper 集群中的其他服务器会首先将自身的状态信息变为 LOOKING 状态,该状态表示服务器已经做好选举新 Leader 服务器的准备了,这之后整个 ZooKeeper 集群开始进入选举新的 Leader 服务器过程。
发起投票:首先每个集群中的服务器都会投票给自己,将投票信息中的 Zxid 和 myid 分别指向本机服务器。
接收投票
统计投票
在leader选举期间接收到事务性请求操作的时候,ZooKeeper 服务会先将这个会话进行挂起操作,挂起的会话不会计算会话的超时时间,之后在 Leader 服务器产生后系统会同步执行这些会话操作。
数据同步
为什么要进行数据同步:保证数据的最终一致性
同步条件:首先需要 ZooKeeper 集群中存在用来进行数据同步的 Learning 服务器。
同步过程
务性的会话请求会被同步,而像数据节点的查询等非事务性请求则不在数据同步的操作范围内
同步方式
DIFF 同步:DIFF 同步即差异化同步的方式
TRUNC+DIFF 同步
TRUNC 同步
SNAP 同步
同步后处理:数据同步的本质就是比对 Leader 服务器与 Learning 服务器,将 Leader 服务器上的数据增加到 Learnning 服务器,再将 Learnning 服务器上多余的事物日志回滚
底层实现:Learner.syncWithLeader( )
事务请求处理
zk集群判断是否是事务性请求--》leader服务器处理--》执行请求--》同步数据
setData
预处理阶段:接收网络请求(PrepRequestProcessor )--》验证权限和超时--》封装会话(setDataRequest )--》提交到处理队列(outstandingChanges )
事务处理阶段: 提交、同步、统计
事务执行阶段:将该请求会话的事务头和事务体信息直接交给内存数据库 ZKDatabase 进行事务性的持久化操作
响应客户端:setDataResponse
ZooKeeper 集群在处理事务性请求操作时,要在 ZooKeeper 集群中对该事务性的请求发起投票,只有超过半数的 Follow 服务器投票一致,才会执行该条写入操作。
数据一致性
Leadeer发起事务一致性投票
投票通过
leader执行事务性请求
进行数据一致性操作
LearnerHandler
非事务请求处理
查询会话请求,会将该客户端请求分配给 Follow 服务器进行处理。而在 Follow 服务器的内部,也采用了责任链的处理模式来处理来自客户端的每一个会话请求。
FollowerRequestProcessor
CommitProcessor
选举过程
判断leader失效:Follow 服务器会定期向 Leader 服务器发送 网络请求
重新选举:Follow 服务器的状态变更为 LOOKING 状态
follow角色变更:follow--》leader
数据同步:ZooKeeper 集群在对外提供服务之前,会通过 Leader 角色服务器管理同步其他角色服务器,具体的数据同步方法
数据和文件
内存数据
事务日志数据
数据同步发送的就是leader的事务日志
数据快照数据
数据快照的作用是将内存数据结构存储到本地磁盘中
在 ZooKeeper 服务运行的过程中,数据快照每间隔一段时间,就会把 ZooKeeper 内存中的数据存储到磁盘中
磁盘数据
实战篇
实现分布式锁
排他锁:只有具有该锁的事务线程可以访问该条数据对象,直到该条事务主动释放锁
共享锁:只对数据对象的写操作加锁,而不为对象的读操作进行加锁
共享锁为一个数据事务创建两个数据节点,来区分是写入操作还是读取操作
分布式 ID 生成器
实现负载均衡
轮询法、随机法、一致性hash、加权轮询
注册中心
在整个 Dubbo 服务的启动过程中,服务提供者会在启动时向 /dubbo/com.foo.BarService/providers 目录写入自己的 URL 地址
ZAB 协议
Zookeeper 是一个为分布式应用提供高效且可靠的分布式协调服务。在解决分布式一致性方面,Zookeeper 并没有使用 Paxos ,而是采用了 ZAB 协议。
ZAB 协议全称:Zookeeper Atomic Broadcast(Zookeeper 原子广播协议)是 ZooKeeper 专门设计用来解决集群最终一致性问题的算法,它的两个核心功能点是崩溃恢复和原子广播协议。
整个 Zookeeper 就是在这两个模式之间切换。 简而言之,当 Leader 服务可以正常使用,就进入消息广播模式,当 Leader 不可用时,则进入崩溃恢复模式。
崩溃恢复
广播模式:在 Leader 节点服务器处理请求后,需要通知集群中的其他角色服务器进行数据同步。ZooKeeper 集群采用消息广播的方式发送通知。
数据同步
发送询问事务执行
反馈执行结果
统计投票结果过半数
执行事务commit操作
原子广播模式(写请求)
1.leader从客户端收到一个写请求后生成一个新的事务并为这个事务生成一个唯一的ZXID,
2.leader将将带有 zxid 的消息作为一个提案(proposal)分发给所有 FIFO队列。
3.FIFO队列取出队头proposal给follower节点。
4.当 follower 接收到 proposal,先将 proposal 写到硬盘,写硬盘成功后再向 leader 回一个 ACK。
5.FIFO队列把ACK返回给Leader。
6.当leader收到超过一半以上的follower的ack消息,leader会进行commit请求,然后再给FIFO发送commit请求。
7.当follower收到commit请求时,会判断该事务的ZXID是不是比历史队列中的任何事务的ZXID都小,如果是则提交,如果不是则等待比它更小的事务的commit(保证顺序性)
总结
1.将数据都复制到 Follwer 中
2.等待 Follwer 回应 Ack,最低超过半数即成功
3.当超过半数成功回应,则执行 commit ,同时提交自己
4.从节点是异步commint
Paxos算法
在分布式一致性问题的解决方案中,Paxos 算法可以说是目前最为优秀的
Paxos 算法是基于消息传递的分布式一致性算法,在服务器发生宕机故障的时候,能够保证数据的完整性,不要求可靠的消息传递,可容忍消息丢失、延迟、乱序以及重复,保证服务的高可用性。
保证分布式系统下数据的一致性操作,本质是协调运行在不同的网络服务器上的线程服务,使这些服务就某一个特定的数据执行一致性的变更操作。
底层实现
提议者(Proposer):提出提案(Proposal)。Proposal 信息包括提案编号(Proposal ID)和提议的值(Value)
决策者(Acceptor):参与决策,回应 Proposers 的提案。收到 Proposal 后可以接受提案,若 Proposal 获得超过半数 Acceptors 的许可,则称该 Proposal 被批准
决策学习者:不参与决策,从 Proposers/Acceptors 学习最新达成一致的提案(Value)
事务处理过程
提案准备阶段
在 Paxos 算法中,当处理来自客户端的事务性会话请求的过程时,首先会触发一个或多个服务器进程,就本次会话的处理发起提案
事务处理阶段
Proposer 提案服务器会再次向 Acceptor 决策者服务器发送 propose 提交请求
数据同步阶段
Paxos 算法将针对本次执行结果形成一个决议,并发送给 Learner 服务器。当 Learner 服务器接收到该条决议信息后,会同步 Acceptor 决策者服务器上的数据信息,最终完成该条事务性会话在整个集群中的处理。
ZAB协议与Paxos区别
相同之处是,在执行事务行会话的处理中,两种算法最开始都需要一台服务器或者线程针对该会话,在集群中发起提案或是投票。只有当集群中的过半数服务器对该提案投票通过后,才能执行接下来的处理。
发起投票的机器:zk所采用的是在集群中运行的一台 Leader 角色服务器。而 Paxos 算法则采用多副本的处理方式
收藏
0 条评论
下一页