zookeeper的原理

1.zookeeper集群角色
2.leader选举源码分析
3.ZAB协议
4.ZAB崩溃恢复模式
5.watch模式源码分析
6.数据存储
7.参考

 

1.zookeeper集群角色

a)leader

leader是zookeeper集群的核心。

1.事务请求的唯一调度者和处理者,保证集群事务处理的顺序性

2.集群内部各个服务器的调度者

b)follower

1.处理客户端非事务请求,以及转发事务请求给leader服务器

2.参与事务请求提议(proposal)的投票(客户端的一个事务请求,需要半数服务器投票通过以后才能通知leader commit; leader会发起一个提案,要求follower投票)

3.参与leader选举的投票

c)observer

观察zookeeper集群中最新状态的变化并将这些状态同步到observer服务器上

增加observer不影响集群中事务处理能力,同时还能提升集群的非事务处理能力

2.leader选举源码分析

源码地址:https://github.com/apache/zookeeper.git

需要的条件: jdk 1.7以上 、ant 、idea

a)找入口

zookeeper启动的时候有个日志输出,可以根据日志输出来跟踪查看leader选举

b)分析

>QuorumPeer.startLeaderElection

-->createElectionAlgorithm(三种选举算法leaderElection/AuthFastLeaderElection/FastLeaderElection

-->currentVote = new Vote(myid, getLastLoggedZxid(), getCurrentEpoch());//初始化自己的投票信息

--->getCurrentEpoch>readLongFromFile  从/tmp/zookeeper 里面读取数据Epoch

--->QuorumCnxManager 初始化数据,管理选举中和其他server的网络交互,选举时监听在专门的electionAddr上

---->receiveConnection 监听到数据返回,判断sid,sid越大代表权重高,其他服务器需要与该sid服务器建立连接

--->FastLeaderElection 默认选举算法

---->Messenger(就是QuorumCnxManager )

----->WorkerSender>从QuorumCnxManager::recvQueue中获取网络包,并将其发到FastLeaderElection::recvqueue中

----->WorkerReceiver>从FastLeaderElection::sendqueue中获取网络包,并将其放QuorumCnxManager::queueSendMap中,并发送到网络上

----->lookForLeader>QuorumPeer主线程会调用lookForLeader函数,它从recvqueue中获取别人发给server的选举数据,并将发给其他server的投票放到sendqueue中

c)概念

serverid : 在配置server集群的时候,给定服务器的标识id(myid)

zxid  : 服务器在运行时产生的数据ID, zxid的值越大,表示数据越新

Epoch: 选举的轮数

server的状态:Looking、 Following、Observering、Leading

参考:https://www.cnblogs.com/siodoon/articles/5438076.html

d)流程总结

第一次初始化启动的时候server的状态: LOOKING

1.所有在集群中的server都会推荐自己为leader,然后把(myid、zxid、epoch)作为广播信息,广播给集群中的其他server, 然后等待其他服务器返回

2.每个服务器都会接收来自集群中的其他服务器的投票。集群中的每个服务器在接受到投票后,开始判断投票的有效性

a)判断逻辑时钟(Epoch) ,如果Epoch大于自己当前的Epoch,说明自己保存的Epoch是过期。更新Epoch,同时clear其他服务器发送过来的选举数据。判断是否需要更新当前自己的选举情况

b)如果Epoch小于目前的Epoch,说明对方的epoch过期了,也就意味着对方服务器的选举轮数是过期的。这个时候,只需要讲自己的信息发送给对方

c)如果Epoch==当前Epoch,则根据规则判断是否有规则获得leader(zxid最大的优先)

3.统计投票

zookeeper的原理_第1张图片

3.ZAB协议

a)ZAB协议要求每个leader都要经历三个阶段,即发现,同步,广播。

(1)发现:即要求zookeeper集群必须选择出一个leader进程,同时leader会维护一个follower可用列表。将来客户端可以这follower中的节点进行通信。

(2)同步:leader要负责将本身的数据与follower完成同步,做到多副本存储。这样也是体现了CAP中高可用和分区容错。follower将队列中未处理完的请求消费完成后,写入本地事物日志中。

(3)广播:leader可以接受客户端新的proposal请求,将新的proposal请求广播给所有的follower。

b)原因

拜占庭将军问题

paxos协议主要就是如何保证在分布式环网络环境下,各个服务器如何达成一致最终保证数据的一致性问题

ZAB协议,基于paxos协议的一个改进

zookeeper并没有完全采用paxos算法, 而是采用zab Zookeeper atomic broadcast

zab协议为分布式协调服务zookeeper专门设计的一种支持崩溃恢复的原子广播协议

c)在zookeeper 的主备模式下,通过zab协议来保证集群中各个副本数据的一致性

d)zookeeper使用的是单一的主进程来接收并处理所有的事务请求,并采用zab协议,把数据的状态变更以事务请求的形式广播到其他的节点

e)zab协议在主备模型架构中,保证了同一时刻只能有一个主进程来广播服务器的状态变更

f)所有的事务请求必须由全局唯一的服务器来协调处理,这个的服务器叫leader,其他的叫follower,leader节点主要负责把客户端的事务请求转化成一个request事务提议(proposal),并分发给集群中的所有follower节点,再等待所有follower节点的反馈ack。一旦超过半数服务器进行了正确的反馈,那么leader就会commit这条消息

zookeeper的原理_第2张图片

g)ZAB协议中主要有两种模式,第一是消息广播模式(第5点);第二是崩溃恢复模式

h)zookeeper集群中为保证任何所有进程能够有序的顺序执行,只能是leader服务器接受写请求,即使是follower服务器接受到客户端的请求,也会转发到leader服务器进行处理

4.ZAB崩溃恢复模式

a)什么情况下zab协议会进入崩溃恢复模式

当服务器启动时

当leader服务器出现网络中断、崩溃或者重启的情况

集群中已经不存在过半的服务器与该leader保持正常通信

b)zab协议进入崩溃恢复模式会做什么

(1)当leader出现问题,zab协议进入崩溃恢复模式,并且选举出新的leader。当新的leader选举出来以后,如果集群中已经有过半机器完成了leader服务器的状态同步(数据同步),退出崩溃恢复,进入消息广播模式

(2)退出崩溃恢复的要求:

确保已经被leader提交的proposal必须最终被所有的follower服务器提交。

确保丢弃已经被leader出的但是没有被提交的proposal。

(3)新选举出来的leader不能包含未提交的proposal,即新选举的leader必须都是已经提交了的proposal的follower服务器节点。同时,新选举的leader节点中含有最高的ZXID。这样做的好处就是可以避免了leader服务器检查proposal的提交和丢弃工作。

(4)当新的机器加入到集群中的时候,如果已经存在leader服务器,那么新加入的服务器就会自觉进入数据恢复模式,找到leader进行数据同步

c)进入崩溃模式的场景

(1)leader在提出proposal时未提交之前崩溃,则经过崩溃恢复之后,新选举的leader一定不能是刚才的leader。因为这个leader存在未提交的proposal。

(2)leader在发送commit消息之后,崩溃。即消息已经发送到队列中。经过崩溃恢复之后,参与选举的follower服务器(刚才崩溃的leader有可能已经恢复运行,也属于follower节点范畴)中有的节点已经是消费了队列中所有的commit消息。即该follower节点将会被选举为最新的leader。剩下动作就是数据同步过程

c)数据同步

(1)在zookeeper集群中新的leader选举成功之后,leader会将自身的提交的最大proposal的事物ZXID发送给其他的follower节点。follower节点会根据leader的消息进行回退或者是数据同步操作。最终目的要保证集群中所有节点的数据副本保持一致。

(2)数据同步完之后,zookeeper集群如何保证新选举的leader分配的ZXID是全局唯一呢?这个就要从ZXID的设计谈起。

ZXID是一个长度64位的数字,其中低32位是按照数字递增,即每次客户端发起一个proposal,低32位的数字简单加1。高32位是leader周期的epoch编号,至于这个编号如何产生(我也没有搞明白),每当选举出一个新的leader时,新的leader就从本地事物日志中取出ZXID,然后解析出高32位的epoch编号,进行加1,再将低32位的全部设置为0。这样就保证了每次新选举的leader后,保证了ZXID的唯一性而且是保证递增的。

zookeeper的原理_第3张图片

d)问题

(1)假设一个事务在leader服务器被提交了,并且已经有过半的follower返回了ack。 在leader节点把commit消息发送给folower机器之前leader服务器挂了怎么办

zab协议,一定需要保证已经被leader提交的事务也能够被所有follower提交

zab协议需要保证,在崩溃恢复过程中跳过哪些已经被丢弃的事务

(2)主从架构下,leader 崩溃,数据一致性怎么保证?

leader 崩溃之后,集群会选出新的 leader,然后就会进入恢复阶段,新的 leader 具有所有已经提交的提议,因此它会保证让 followers 同步已提交的提议,丢弃未提交的提议(以 leader 的记录为准),这就保证了整个集群的数据一致性。

(3)选举 leader 的时候,整个集群无法处理写请求的,如何快速进行 leader 选举?

这是通过 Fast Leader Election 实现的,leader 的选举只需要超过半数的节点投票即可,这样不需要等待所有节点的选票,能够尽早选出 leader

参考

https://blog.csdn.net/junchenbb0430/article/details/77583955

https://yq.aliyun.com/articles/304722

5.watch模式源码分析

可以通过zk.exists、zk.getData进行监听,监听一次就没了

找入口,第一遍找主干,第二遍再回顾

1)客户端注册监听

>getData(final String path, Watcher watcher, DataCallback cb, Object ctx)

->WatchRegistration(3种监听模式)

-->ExistsWatchRegistration

-->DataWatchRegistration

-->ChildWatchRegistration

->cnxn.queuePacket 注册事件

-->sendThread.getClientCnxnSocket().packetAdded()  

--->sendThread类分析

2)服务器数据变化把客户端监听的事件通知给客户端

3)关键类

zookeeper的原理_第4张图片

Watcher,接口类型,其定义了process方法,需子类实现。

Event,接口类型,Watcher的内部类,无任何方法。

KeeperState,枚举类型,Event的内部类,表示Zookeeper所处的状态。

EventType,枚举类型,Event的内部类,表示Zookeeper中发生的事件类型。

WatchedEvent,表示对ZooKeeper上发生变化后的反馈,包含了KeeperState和EventType。

ClientWatchManager,接口类型,表示客户端的Watcher管理者,其定义了materialized方法,需子类实现。

ZKWatchManager,Zookeeper的内部类,继承ClientWatchManager。

MyWatcher,ZooKeeperMain的内部类,继承Watcher。

ServerCnxn,接口类型,继承Watcher,表示客户端与服务端的一个连接。

WatchManager,管理Watcher。

4)总结

zookeeper的原理_第5张图片

1.客户端先把事件存储在WatchManger

2.同时把事件注册到zookeeper服务器

3.服务器返回事件通知客户端

4.客户端去WatchManger找到对应节点的事件发送通知

参考:https://www.cnblogs.com/leesf456/p/6286827.html

6.数据存储

1)内存数据和磁盘数据

zookeeper会定时把数据存储在磁盘上。

配置里面的DataDir = 存储的是数据的快照

快照: 存储某一个时刻全量的内存数据内容

2)DataLogDir 存储事务日志

文件命名方式 log.zxid

查看事务日志的命令

java -cp :/data/program/zookeeper-3.4.10/lib/slf4j-api-1.6.1.jar:/data/program/zookeeper-3.4.10/zookeeper-3.4.10.jar org.apache.zookeeper.server.LogFormatter log.200000001

3)zookeeper 有三种日志

zookeeper.out  //运行日志

快照     存储某一时刻的全量数据

事务日志 事务操作的日志记录

7.参考

http://blog.jobbole.com/104985/ 

你可能感兴趣的:(zookeeper)