引言
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务。
具体的安装可以参考我另一篇文章:zookeeper-安装
python操作zk可以参考我的这篇文章:zookeeper-python操作zookeeper
这里对zookeeper做一些整体上的介绍
(顺便推广下我的微信公众号:龙叔18岁)
1·ZK的整体架构
1.1·集群——机器节点
节点角色 | 描述 | |
leader | 负责系统的写请求,事务请求的唯一调度和处理者,保证集群事务处理的顺序性。集群内部各服务器的调度者。 | |
learner | follower | 接受客户端连接,可直接处理读请求,写请求会转发给leader处理;follower还要处理leader的提议,并在leader提交该提议时在本地也进行提交;并参与leader选举 |
observer | Observer和Follower比较相似,只有一些小区别:首先observer不属于法定人数,即不参加选举也不响应提议;其次是observer不需要将事务持久化到磁盘,一旦observer被重启,需要从leader重新同步整个名字空间。 Observer不参加ZooKeeper的事务提交和选举。 |
1.1.1·客户端连接server节点读操作
读请求由客户端所连接到的server直接处理返回,但是因为iserver节点之间数据同步会有网络延迟等问题,不同客户端读到的数据可能不一样
zookeeper保证各节点最终的数据一致,如果需要最新数据,可以在读数据之前调用sync()接口
注解:zookeeper的sync
sync是使得client当前连接着的ZooKeeper服务器,和ZooKeeper的Leader节点同步(sync)一下数据。
当follower收到到sync请求时,会将这个请求添加到一个pendingSyncs队列里,然后将这个请求发送给leader,直到收到leader的Leader.SYNC消息时,才将这个请求从pendingSyncs队列里移除,并commit这个请求。
当Leader收到一个sync请求时,如果leader当前没有待commit的决议,那么leader会立即发送一个Leader.SYNC消息给follower。否则,leader会等到当前最后一个待commit的决议完成后,再发送Leader.SYNC消息给Follower。
如果leader和follower之间的消息通信,是严格按顺序来发送的(TCP保证),因此,当follower接收到Leader.SYNC消息时,说明follower也一定接收到了leader之前(在leader接收到sync请求之前)发送的所有提案或者commit消息。这样,就可以确保follower和leader是同步的了。
1.1.2·客户端连接server节点写操作
节点角色 | leader | follower | observer |
写操作流程 |
|
|
|
注意点 | 【1】leader只给follower发送proposal【提议】 【2】半数以上follower返回ack,leader就视为该事务成功,并给其他所有节点发送commit |
1.2·ZNode——数据节点
节点类型 | 命令 | 描述 | |
持久节点 | [zk: localhost:2181(CONNECTED) 25] create /zkFirst/zk2020/11/08/aa "aa" Created /zkFirst/zk2020/11/08/aa | 创建后永久存在,除非主动删除 | |
临时节点 | [zk: localhost:2181(CONNECTED) 26] create -e /zkFirst/zk2020/11/08/bb "bb" Created /zkFirst/zk2020/11/08/bb | 临时创建的,会话结束节点自动被删除,也可以手动删除,临时节点不能拥有子节点 | |
顺序节点 | 持久顺序节点 | [zk: localhost:2181(CONNECTED) 27] create -s /zkFirst/zk2020/11/08/cc "cc" Created /zkFirst/zk2020/11/08/cc0000000015 | Zookeeper将10位的序列号加到原始名称来设置znode的路径给 |
临时顺序节点 | [zk: localhost:2181(CONNECTED) 28] create -s -e /zkFirst/zk2020/11/08/dd "dd" Created /zkFirst/zk2020/11/08/dd0000000016 |
2·watcher——对ZNode进行监控
ZK允许客户端向服务端注册一个Watcher监听,当服务点的的指定事件触发监听时,那么服务端就会向客户端发送事件通知,以便客户端完成逻辑操作
(即客户端向服务端注册监听,并将watcher对象存在客户端的Watchermanager中,服务端触发事件后,向客户端发送通知,客户端收到通知后从wacherManager中取出对象来执行回调逻辑)
2.1·watcher整体流程图
2.2·可设置watcher的函数
getData、getChildren、exist接口
2.3·可触发watcher的事件
事件 | 说明 |
NodeCreated (1) | Watcher监听的数据节点被创建时 |
NodeDeleted (2) | Watcher监听的数据节点被删除时 |
NodeDataChanged (3) | Watcher监听的数据节点内容发生变更时(无论内容数据是否变化) |
NodeChildrenChanged (4) | Watcher监听的数据节点的子节点列表发生变更时 |
2.4·watcher的特性&注意点
1·Watcher是一次性的,一旦被触发就会移除,再次使用时需要重新注册
2·Watcher回调是顺序串行化执行的,只有回调后客户端才能看到最新的数据状态。一个Watcher回调逻辑不应该太多,以免影响别的watcher执行
3·WatchEvent是最小的通信单元,结构上只包含通知状态、事件类型和节点路径,并不会告诉数据节点变化前后的具体内容
4·Watcher只有在当前session彻底失效时才会无效,若在session有效期内快速重连成功,则watcher依然存在,仍可接收到通知
3·ZAB
ZooKeeper Atomic Broadcast (ZAB, ZooKeeper原子消息广播协议)是ZooKeeper实现分布式数据一致性的核心算法,ZAB借鉴Paxos算法,但又不像Paxos算法(一种基于消息传递的一致性算法)那样,是一种通用的分布式一致性算法,它是一种特别为ZooKeeper专门设计的支持崩溃恢复的原子广播协议。
根据ZAB协议,所有的写操作都必须通过leader来完成,leader写入本地日志后再复制到所有的follower节点。如果客户端对follower/observer发起写请求,follower/observer会将请求转发到leader,然后由leader处理完成后再将结果转发回follower/observer发送给客户端。
ZAB协议分为消息广播和崩溃恢复模式
3.1·协议过程
3.2·消息广播
1. 客户端发起一个写操作请求
2. Leader服务器将客户端的request请求转化为事物proposql提案,同时为每个proposal分配一个全局唯一的ID,即ZXID。
3. leader服务器与每个follower之间都有一个队列,leader将消息发送到该队列
4. follower机器从队列中取出消息处理完(写入本地事物日志中)毕后,向leader服务器发送ACK确认。
5. leader服务器收到半数以上的follower的ACK后,即认为可以发送commit
6. leader向所有的follower服务器发送commit消息。
关键词注解:
1.ZXID:·在消息广播中,leader会将每一个事务请求生成proposal,并在对其进行广播之前给这个事务proposal生成一个全局唯一的递增的 事务id,这个事务id就是ZXID,zookeeper会按照ZXID的先后顺序对事务进行处理,保证了事务的顺序执行。
·ZXID是一个64位的数字:
【低32位】可以看成一个简单的单增计数器,针对客户端每一个事务请求,Leader 在产生新的 Proposal 事务时,都会对该计数器加1。
【高32位】则代表了 Leader 周期的 epoch 编号。
(epoch 编号可以理解为当前集群所处的年代,或者周期。每次Leader变更之后都会在 epoch 的基础上加1,这样旧的 Leader 崩溃恢复之后,其他Follower 也不会听它的了,因为 Follower 只服从epoch最高的 Leader 命令)
·每当选举产生一个新的 Leader ,就会从这个 Leader 服务器上取出本地事务日志充最大编号 Proposal 的 zxid,并从 zxid 中解析得到对应的 epoch 编号,然后再对其加1,之后该编号就作为新的 epoch 值,并将低32位数字归零,由0开始重新生成zxid。
2.FIFO消息队列:每个follower都有一个FIFO的消息队列,用于leader和follower之间收发消息,使用队列,leader与follower只需要往队列中发送消息即可,实现异步,避免了同步可能造成的阻塞,队列是FIFO的,保证了事务的顺序执行。
3.3·崩溃恢复
在集群启动和集群运行期间leader异常的时候,会进入崩溃恢复模式进行leader的选举
3.3.1·相关名词解释
这些关键词在日志中也可以看到,
·WorkerReceiver:接收投票信息工作线程
·WorkerSender:发送投票信息的工作线程
·QuorumPeer:这个类就是zookeeper的Leader选举的启动类,负责创建选举算法,zk数据恢复,启动leader选举等
·QuorumCnxManager(qcm): 实现领导选举中的网络连接管理功能。它为每一对节点维护唯一的一个连接,在两个节点都启动申请连接时,只有sid大的一方才会申请连接成功。qcm对每个节点维护一个消息发送队列。
·NIOServerCnxn:处理与客户端之间的通信,使用单线程处理
·LearnerHandler:
为了保证整个集群内部的实时通信,同时为了确保可以控制所有的Follower/Observer服务器,Leader服务器会与每个Follower/Observer服务器建立一个TCP长连接。同时也会为每个Follower/Observer服务器创建一个名为LearnerHandler的实体。
LearnerHandler是Learner服务器的管理者,主要负责Follower/Observer服务器和Leader服务器之间的一系列网络通信,包括数据同步、请求转发和Proposal提议的投票等。
Leader服务器中保存了所有Follower/Observer对应的LearnerHandler。
Leader和每个Learner连接会维持一个长连接,并有一个单独的LearnerHandler线程和一个Learner进行交互
·peerEpoch:每次leader选举完成之后,都会选举出一个新的peerEpoch,用来标记事务请求所属的轮次
·electionEpoch:每执行一次leader选举,electionEpoch就会自增,用来标记leader选举的轮次
·peerLastZxid:Learner服务器(Follower或observer)最后处理的zxid。
·lastProcessedZxid:最后一次commit的事务请求的zxid(leader服务器最大的ZXID)
·minCommittedLog:Leader服务器proposal缓存队列committedLog中的最小的zxid。
·maxCommittedLog:Leader服务器proposal缓存队列committedLog中的最大的zxid。
3.3.2·成为leader的条件
1)选 epoch 最大的
2)若 epoch 相等,选 zxid 最大的
3)若 epoch 和 zxid 相等,选择 server_id 最大的(zoo.cfg中的myid)
Zab协议需要保证选举出来的Leader需要满足以下条件:
1)新选举出来的 Leader 不能包含未提交的 Proposal 。
即新选举的 Leader 必须都是已经提交了 Proposal 的 Follower 服务器节点。
2)新选举的 Leader 节点中含有最大的 zxid 。
这样做的好处是可以避免 Leader 服务器检查 Proposal 的提交和丢弃工作。
3.3.3·选举过程中节点的服务器状态
在leader选举过程中,服务器有下面四种状态:
·LOOKING:寻找leader状态,只要当前服务器状态为LOOKING,进入循环,不断地读取其它Server发来的通知、进行比较、更新自己的投票、发送自己的投票、统计投票结果,直到leader选出或出错退出。
·LEADING:领导状态(节点为leader)
·FOLLOWING:跟随者状态
·OBSERVING:观察者状态(此状态不参与选举)
3.3.4·集群启动时的选举过程
因为选举需要至少两台机器,所以当启动两个服务器的时候,选举就开始了,换句话说,集群启动的时候,leader会在最开始启动的两个服务器中选举出来
这里以server-1(myid=1),server-2(myid=2),server-3(myid=3),三个服务器节点的集群为例:
【1】选举示意图
【2】集群启动的日志解读
【第一步】先启动server-1
日志报错连接不上另外两个节点,目前集群是不可用的,SERVER-1一开始进入LOOKING状态
【第二步】再启动server-2
目前有了两个节点,则开始leader选举,因为ZXID相同,所以选举了myid较大的server-2
——新起的server-2节点日志:
【leader选举】
2020-11-17 23:36:44,418 [myid:2] - INFO [main:QuorumCnxManager$Listener@878] - Election port bind maximum retries is 3
2020-11-17 23:36:44,429 [myid:2] - INFO [QuorumPeerListener:QuorumCnxManager$Listener@929] - 2 is accepting connections now, my election bind port: /0.0.0.0:3888【选举监听端口】
2020-11-17 23:36:44,437 [myid:2] - INFO [QuorumPeer[myid=2](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):QuorumPeer@1175] - LOOKING【进入leader选举状态,只要当前服务器状态为LOOKING,进入循环,不断地读取其它Server发来的通知、进行比较、更新自己的投票、发送自己的投票、统计投票结果,直到leader选出或出错退出。】
2020-11-17 23:36:44,438 [myid:2] - INFO [QuorumPeer[myid=2](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):FastLeaderElection@903] - New election. My id = 2, proposed zxid=0x600
000067
2020-11-17 23:36:44,450 [myid:2] - INFO [WorkerReceiver[myid=2]:FastLeaderElection@697] - Notification: 2 (message format version), 2 (n.leader), 0x600000067 (n.zxid), 0x1 (n.round), LOOKING (n.state), 2 (n.sid), 0x6 (n.peerEPoch), LOOKING (my state)0 (n.config version)【WorkerReceiver是接收投票信息工作线程】
2020-11-17 23:36:44,458 [myid:2] - WARN [QuorumConnectionThread-[myid=2]-2:QuorumCnxManager@381] - Cannot open channel to 3 at election address /192.168.30.128:3888【这个时候因为server-3没有启动,所以还在报连不上节点3】
java.net.ConnectException: 拒绝连接 (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method)
。。。【此处省略报错】2020-11-17 23:36:44,464 [myid:2] - INFO [WorkerReceiver[myid=2]:FastLeaderElection@697] - Notification: 2 (message format version), 1 (n.leader), 0x600000067 (n.zxid), 0x1 (n.round), LOOKING (n.state), 1 (n.sid), 0x6 (n.peerEPoch), LOOKING (my state)0 (n.config version)
2020-11-17 23:36:44,464 [myid:2] - INFO [WorkerReceiver[myid=2]:FastLeaderElection@697] - Notification: 2 (message format version), 2 (n.leader), 0x600000067 (n.zxid), 0x1 (n.round), LOOKING (n.state), 1 (n.sid), 0x6 (n.peerEPoch), LOOKING (my state)0 (n.config version)
2020-11-17 23:36:44,667 [myid:2] - INFO [QuorumPeer[myid=2](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):QuorumPeer@1263] - LEADING【leader选举结束,进入leader状态】
。。。【省略一些信息类日志】
2020-11-17 23:37:07,201 [myid:2] - INFO [QuorumPeer[myid=2](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):Leader@464] - LEADING - LEADER ELECTION TOOK - 22535 MS【选举结束:server-2被选举成为leader节点】
2020-11-17 23:37:07,211 [myid:2] - INFO [QuorumPeer[myid=2](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):FileTxnSnapLog@404] - Snapshotting: 0x600000067 to /usr/local/zookeeper/data/version-2/snapshot.600000067
2020-11-17 23:37:07,246 [myid:2] - INFO [LearnerHandler-/192.168.30.133:34174:LearnerHandler@406] - Follower sid: 1 : info : 192.168.30.133:2888:3888:participant【leader与server-1这个follower节点维持一个长连接】
2020-11-17 23:37:07,262 [myid:2] - INFO [LearnerHandler-/192.168.30.133:34174:ZKDatabase@295] - On disk txn sync enabled with snapshotSizeFactor 0.33【选举完成之后的数据同步】
2020-11-17 23:37:07,262 [myid:2] - INFO [LearnerHandler-/192.168.30.133:34174:LearnerHandler@708] - Synchronizing with Follower sid: 1 maxCommittedLog=0x600000067 minCommittedLog=0x600000001 lastProcessedZxid=0x600000067 peerLastZxid=0x600000067【follower-1 最后处理的ZXID是0x600000067(peerLastZxid),Leader服务器(server-2)提交在队列中的最小zxid为0x600000001 (minCommittedLog),最大zxid为0x600000067 (maxCommittedLog),因为minCommittedLog<=peerLastZxid<=maxCommittedLog,所以选用同步方式位diff】
2020-11-17 23:37:07,263 [myid:2] - INFO [LearnerHandler-/192.168.30.133:34174:LearnerHandler@752] - Sending DIFF zxid=0x600000067 for peer sid: 1【向server-1发起diff数据同步】
2020-11-17 23:37:07,293 [myid:2] - INFO [QuorumPeer[myid=2](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):Leader@1296] - Have quorum of supporters, sids: [ [1, 2],[1, 2] ]; starting up and setting last processed zxid: 0x700000000
2020-11-17 23:37:07,313 [myid:2] - INFO [QuorumPeer[myid=2](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):CommitProcessor@256] - Configuring CommitProcessor with 1 worker threads.
2020-11-17 23:37:07,320 [myid:2] - INFO [QuorumPeer[myid=2](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):ContainerManager@64] - Using checkIntervalMs=60000 maxPerMinute=10000
2020-11-17 23:37:37,587 [myid:2] - INFO [SessionTracker:ZooKeeperServer@398] - Expiring session 0x3000001567a0001, timeout of 30000ms exceeded
2020-11-17 23:37:37,588 [myid:2] - INFO [SessionTracker:QuorumZooKeeperServer@157] - Submitting global closeSession request for session 0x3000001567a0001
2020-11-17 23:37:37,590 [myid:2] - INFO [SyncThread:2:FileTxnLog@218] - Creating new log file: log.700000001
——server-1节点日志:
【leader选举】
2020-11-17 23:36:44,455 [myid:1] - INFO [/0.0.0.0:3888:QuorumCnxManager$Listener@936] - Received connection request from /192.168.30.135:49736【这里接收到了server-2的连接】
2020-11-17 23:36:44,463 [myid:1] - INFO [WorkerReceiver[myid=1]:FastLeaderElection@697] - Notification: 2 (message format version), 2 (n.leader), 0x600000067 (n.zxid), 0x1 (n.round), LOOKING (n.state), 2 (n.sid), 0x6 (n.peerEPoch), LOOKING (my state)0 (n.config version)【WorkerReceiver是接收投票信息工作线程】
2020-11-17 23:36:44,465 [myid:1] - INFO [WorkerReceiver[myid=1]:FastLeaderElection@697] - Notification: 2 (message format version), 2 (n.leader), 0x600000067 (n.zxid), 0x1 (n.round), LOOKING (n.state), 1 (n.sid), 0x6 (n.peerEPoch), LOOKING (my state)0 (n.config version)
2020-11-17 23:36:44,466 [myid:1] - WARN [QuorumConnectionThread-[myid=1]-5:QuorumCnxManager@381] - Cannot open channel to 3 at election address /192.168.30.128:3888【这个时候因为server-3没有启动,所以还在报连不上节点3】
java.net.ConnectException: 拒绝连接 (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method)
。。。【此处省略报错】
2020-11-17 23:36:44,667 [myid:1] - INFO [QuorumPeer[myid=1](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):QuorumPeer@1251] - FOLLOWING【leader选举结束,进入follower状态】
2020-11-17 23:36:44,677 [myid:1] - INFO [QuorumPeer[myid=1](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):Learner@91] - TCP NoDelay set to: true【这个类就是zookeeper的Leader选举的启动类,负责创建选举算法,zk数据恢复,启动leader选举等】
2020-11-17 23:36:52,893 [myid:1] - INFO [NIOWorkerThread-2:NIOServerCnxn@518] - Processing srvr command from /127.0.0.1:39132【NIOServerCnxn处理与客户端之间的通信,使用单线程处理】
。。。【省略一些信息类日志】
2020-11-17 23:37:07,193 [myid:1] - INFO [QuorumPeer[myid=1](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):Follower@69] - FOLLOWING - LEADER ELECTION TOOK - 22526 MS【选举结束:server-1被选举成为follower节点】【选举完成之后的数据同步】
2020-11-17 23:37:07,276 [myid:1] - INFO [QuorumPeer[myid=1](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):Learner@391] - Getting a diff from the leader 0x600000067【接收到leader的diff同步请求】
2020-11-17 23:37:07,286 [myid:1] - INFO [QuorumPeer[myid=1](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):Learner@546] - Learner received NEWLEADER message
2020-11-17 23:37:07,324 [myid:1] - INFO [QuorumPeer[myid=1](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):Learner@529] - Learner received UPTODATE message
2020-11-17 23:37:07,327 [myid:1] - INFO [QuorumPeer[myid=1](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):CommitProcessor@256] - Configuring CommitProcessor with 1 worker threads.
2020-11-17 23:37:37,598 [myid:1] - WARN [QuorumPeer[myid=1](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):Follower@125] - Got zxid 0x700000001 expected 0x1
2020-11-17 23:37:37,599 [myid:1] - INFO [SyncThread:1:FileTxnLog@218] - Creating new log file: log.700000001
【第三步】再启动server-3
因为集群已经有了leader,所以server-3作为了follower加入了集群
server-2节点(leader)的日志:
2020-11-17 23:38:17,051 [myid:2] - INFO [/0.0.0.0:3888:QuorumCnxManager$Listener@936] - Received connection request from /192.168.30.128:47270
2020-11-17 23:38:17,069 [myid:2] - INFO [WorkerReceiver[myid=2]:FastLeaderElection@697] - Notification: 2 (message format version), 3 (n.leader), 0x600000067 (n.zxid), 0x1 (n.round), LOOKING (n.state), 3 (n.sid), 0x6 (n.peerEPoch), LEADING (my state)0 (n.config version)
2020-11-17 23:38:17,108 [myid:2] - INFO [LearnerHandler-/192.168.30.128:33790:LearnerHandler@406] - Follower sid: 3 : info : 192.168.30.128:2888:3888:participant
2020-11-17 23:38:17,111 [myid:2] - INFO [LearnerHandler-/192.168.30.128:33790:ZKDatabase@295] - On disk txn sync enabled with snapshotSizeFactor 0.33
2020-11-17 23:38:17,111 [myid:2] - INFO [LearnerHandler-/192.168.30.128:33790:LearnerHandler@708] - Synchronizing with Follower sid: 3 maxCommittedLog=0x700000001 minCommittedLog=0x600000001 lastProcessedZxid=0x700000001 peerLastZxid=0x600000067
2020-11-17 23:38:17,111 [myid:2] - INFO [LearnerHandler-/192.168.30.128:33790:LearnerHandler@769] - Using committedLog for peer sid: 3
2020-11-17 23:38:17,111 [myid:2] - INFO [LearnerHandler-/192.168.30.128:33790:LearnerHandler@859] - Sending DIFF zxid=0x700000001 for peer sid: 3
2020-11-17 23:39:36,552 [myid:2] - INFO [NIOWorkerThread-1:FourLetterCommands@234] - The list of known four letter word commands is : [{1936881266=srvr, 1937006964=stat, 2003003491=wchc, 1685417328=dump, 1668445044=crst, 1936880500=srst, 1701738089=envi, 1668247142=conf, -720899=telnet close, 2003003507=wchs, 2003003504=wchp, 1684632179=dirs, 1668247155=cons, 1835955314=mntr, 1769173615=isro, 1920298859=ruok, 1735683435=gtmk, 1937010027=stmk}]
2020-11-17 23:39:36,552 [myid:2] - INFO [NIOWorkerThread-1:FourLetterCommands@235] - The list of enabled four letter word commands is : [[srvr]]
2020-11-17 23:39:36,552 [myid:2] - INFO [NIOWorkerThread-1:NIOServerCnxn@518] - Processing srvr command from /127.0.0.1:35350
server-3节点(新follower)的日志:
2020-11-17 23:38:16,954 [myid:3] - INFO [QuorumPeerListener:QuorumCnxManager$Listener@929] - 3 is accepting connections now, my election bind port: /0.0.0.0:3888
2020-11-17 23:38:16,983 [myid:3] - INFO [QuorumPeer[myid=3](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):QuorumPeer@1175] - LOOKING【寻找leader】
2020-11-17 23:38:16,988 [myid:3] - INFO [QuorumPeer[myid=3](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):FastLeaderElection@903] - New election. My id = 3, proposed zxid=0x600000067
2020-11-17 23:38:16,996 [myid:3] - INFO [WorkerReceiver[myid=3]:FastLeaderElection@697] - Notification: 2 (message format version), 3 (n.leader), 0x600000067 (n.zxid), 0x1 (n.round), LOOKING (n.state), 3 (n.sid), 0x6 (n.peerEPoch), LOOKING (my state)0 (n.config version)
2020-11-17 23:38:17,012 [myid:3] - INFO [WorkerReceiver[myid=3]:FastLeaderElection@697] - Notification: 2 (message format version), 2 (n.leader), 0x600000067 (n.zxid), 0x1 (n.round), LOOKING (n.state), 1 (n.sid), 0x6 (n.peerEPoch), LOOKING (my state)0 (n.config version)
2020-11-17 23:38:17,034 [myid:3] - INFO [WorkerReceiver[myid=3]:FastLeaderElection@697] - Notification: 2 (message format version), 2 (n.leader), 0x600000067 (n.zxid), 0x1 (n.round), FOLLOWING (n.state), 1 (n.sid), 0x7 (n.peerEPoch), LOOKING (my state)0 (n.config version)
2020-11-17 23:38:17,035 [myid:3] - INFO [WorkerReceiver[myid=3]:FastLeaderElection@697] - Notification: 2 (message format version), 2 (n.leader), 0x600000067 (n.zxid), 0x1 (n.round), LOOKING (n.state), 2 (n.sid), 0x6 (n.peerEPoch), LOOKING (my state)0 (n.config version)
2020-11-17 23:38:17,035 [myid:3] - INFO [WorkerReceiver[myid=3]:FastLeaderElection@697] - Notification: 2 (message format version), 2 (n.leader), 0x600000067 (n.zxid), 0x1 (n.round), LEADING (n.state), 2 (n.sid), 0x7 (n.peerEPoch), LOOKING (my state)0 (n.config version)
2020-11-17 23:38:17,037 [myid:3] - INFO [QuorumPeer[myid=3](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):QuorumPeer@1251] - FOLLOWING
。。。【省略一些信息类日志】
2020-11-17 23:38:17,056 [myid:3] - INFO [QuorumPeer[myid=3](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):Follower@69] - FOLLOWING - LEADER ELECTION TOOK - 19 MS【发现集群已有leader,自身成为follower】
2020-11-17 23:38:17,069 [myid:3] - INFO [QuorumPeer[myid=3](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):Learner@391] - Getting a diff from the leader 0x700000001
2020-11-17 23:38:17,072 [myid:3] - WARN [QuorumPeer[myid=3](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):Learner@454] - Got zxid 0x700000001 expected 0x1
2020-11-17 23:38:17,073 [myid:3] - INFO [QuorumPeer[myid=3](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):Learner@546] - Learner received NEWLEADER message
2020-11-17 23:38:17,078 [myid:3] - INFO [QuorumPeer[myid=3](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):Learner@529] - Learner received UPTODATE message
2020-11-17 23:38:17,083 [myid:3] - INFO [QuorumPeer[myid=3](plain=[0:0:0:0:0:0:0:0]:2181)(secure=disabled):CommitProcessor@256] - Configuring CommitProcessor with 1 worker threads.
2020-11-17 23:38:17,113 [myid:3] - INFO [SyncThread:3:FileTxnLog@218] - Creating new log file: log.700000001
2020-11-17 23:39:43,869 [myid:3] - INFO [NIOWorkerThread-1:FourLetterCommands@234] - The list of known four letter word commands is : [{1936881266=srvr, 1937006964=stat, 2003003491=wchc, 1685417328=dump, 1668445044=crst, 1936880500=srst, 1701738089=envi, 1668247142=conf, -720899=telnet close, 2003003507=wchs, 2003003504=wchp, 1684632179=dirs, 1668247155=cons, 1835955314=mntr, 1769173615=isro, 1920298859=ruok, 1735683435=gtmk, 1937010027=stmk}]
2020-11-17 23:39:43,870 [myid:3] - INFO [NIOWorkerThread-1:FourLetterCommands@235] - The list of enabled four letter word commands is : [[srvr]]
2020-11-17 23:39:43,870 [myid:3] - INFO [NIOWorkerThread-1:NIOServerCnxn@518] - Processing srvr command from /127.0.0.1:33432
3.3.5·集群运行期间的选举过程
集群运行期间因为leader节点崩溃会导致leader的选举,整体和集群启动时的leader选举差不多,示意图如下
3.3.6·leader选举之后的数据同步
数据同步方式有四种,决定用哪一种,是根据下面的四个参数
·peerLastZxid:Learner服务器(Follower或observer)最后处理的zxid。
·lastProcessedZxid:最后一次commit的事务请求的zxid(leader服务器最大的ZXID)
·minCommittedLog:Leader服务器proposal缓存队列committedLog中的最小的zxid。
·maxCommittedLog:Leader服务器proposal缓存队列committedLog中的最大的zxid。
【1】同步方式1:DIFF(直接差异化同步)
当Follower最大的zxid小于maxCommittedZxid且大于minCommittedZxid
【2】同步方式2:TRUNC+DIFF(先回滚再差异化同步)
当新的 Leader 服务器发现某个 Learner 服务器包含了一条自己没有的事务记录,那么就需要让该 Learner 服务器进行事务回滚--回滚到 Leader服务器上存在的,同时也是最接近于 peerLastZxid 的 ZXID
【3】同步方式3:TRUNC(仅回滚同步)
当Follower最大的zxid大于maxCommittedZxid时,该方式要求Follower丢弃超出的那部分Proposal
【4】同步方式4:SNAP(全量同步)
当Follower最大的zxid小于minCommittedZxid时,该方式直接同步快照给Follower
或者
Leader 服务器上没有 Proposal 缓存队列且 peerLastZxid 不等 于 lastProcessZxid
5·zookeeper开源辅助工具
zkweb,zkui,Shepher 等等网上可以找到不少开源的zookeeper管理工具,可以根据需要搜索看看
推荐公众号,分享运维知识:龙叔18岁