Zookeeper集群搭建及原理
https://zookeeper.apache.org
https://baike.baidu.com/item/Paxos算法
4.2 ZAB协议
4.2 ZAB协议
ZAB(ZooKeeper Atomic broadcast)即ZooKeeper原子消息广播协议,类似于一个二阶段提交过程(2PC)属于最终一致性。是zookeeper基于Paxos算法的简化实现。
所有事务请求必须由一个全局唯一的服务器来协调处理,这样的服务器被称为 Leader服务器,而余下的其他服务器则成为 Follower服务器。 Leader服务器负责将一个客户端事务请求转换成一个事务 Proposal(提议),并将该 Proposal分发給集群中所有的Follower服务器。之后 Leader服务器需要等待所有 Follower服务器的反馈,一旦超过半数的 Follower服务器进行了正确的反馈后,那么 Leader就会再次向所有的 Follower服务器分发 Commit消息,要求其将前一个 Proposal进行提交。

上图说明:
1:Client向Follower发出写操作;
2:Follower将收到的写请求转发给Leader处理;
3:Leader收到请求后分配一个全局单调递增的唯一的事务ID(即ZXID,按其先后顺序来进行排序与处理);
4.1:Leader服务器会为每一个 Follower服务器都各自分配一个单独的队列,然后将需要广播的事务Proposal依次放入这些队列中去,并且根据FIFO策略进行消息发送;每一个 Follower服务器在接收到这个事务 Proposal之后,都会首先将其以事务日志的形式写入到本地磁盘中去,并且在成功写入后反馈给 Leader服务器个Ack响应。Leader自己也会将事务日志写入磁盘;
4.2:当 Leader服务器接收到超过半数Follower的Ack响应后,就会广播一个Commit消息给所有的 Follower服务器以通知其进行事务提交(写入内存),同时 Leader自身也会完成对事务的提交。
5:由Leader将结果返回给Client1
上图中4.1和4.2步骤,由于Leader自身也计一票,如果Follower2 由于网络等原因没有给Leader Ack响应,但Leader和Follower 1 两票已超过半数,所以结果依然会成功。此时Client2请求Follower2获取“/aaa”数据时,可以通过sync 让Follower 2向Leader同步后再返回数据。
4.3 选举机制
4.3.1 节点网络
基于上面的第2章集群搭建,查看每台节点网络连接情况
yum install net-tools
netstat -natp | egrep '(2888|3888)'
查看结果如下:
# q101信息
[root@q101 ~]# netstat -natp | egrep '(2888|3888)'
tcp6 0 0 192.168.88.101:3888 :::* LISTEN 1924/java
tcp6 0 0 192.168.88.101:58052 192.168.88.102:3888 ESTABLISHED 1924/java
tcp6 0 0 192.168.88.101:39738 192.168.88.103:3888 ESTABLISHED 1924/java
tcp6 0 0 192.168.88.101:54174 192.168.88.102:2888 ESTABLISHED 1924/java
tcp6 0 0 192.168.88.101:47726 192.168.88.104:3888 ESTABLISHED 1924/java
# q102信息
[root@q102 ~]# netstat -natp | egrep '(2888|3888)'
tcp6 0 0 192.168.88.102:2888 :::* LISTEN 1661/java
tcp6 0 0 192.168.88.102:3888 :::* LISTEN 1661/java
tcp6 0 0 192.168.88.102:3888 192.168.88.101:58052 ESTABLISHED 1661/java
tcp6 0 0 192.168.88.102:2888 192.168.88.103:38244 ESTABLISHED 1661/java
tcp6 0 0 192.168.88.102:50104 192.168.88.104:3888 ESTABLISHED 1661/java
tcp6 0 0 192.168.88.102:2888 192.168.88.104:48034 ESTABLISHED 1661/java
tcp6 0 0 192.168.88.102:2888 192.168.88.101:54174 ESTABLISHED 1661/java
tcp6 0 0 192.168.88.102:37466 192.168.88.103:3888 ESTABLISHED 1661/java
# q103信息
[root@q103 ~]# netstat -natp | egrep '(2888|3888)'
tcp6 0 0 192.168.88.103:3888 :::* LISTEN 1415/java
tcp6 0 0 192.168.88.103:38244 192.168.88.102:2888 ESTABLISHED 1415/java
tcp6 0 0 192.168.88.103:3888 192.168.88.101:39738 ESTABLISHED 1415/java
tcp6 0 0 192.168.88.103:3888 192.168.88.102:37466 ESTABLISHED 1415/java
tcp6 0 0 192.168.88.103:58344 192.168.88.104:3888 ESTABLISHED 1415/java
# q104信息
[root@q104 ~]# netstat -natp | egrep '(2888|3888)'
tcp6 0 0 192.168.88.104:3888 :::* LISTEN 1333/java
tcp6 0 0 192.168.88.104:3888 192.168.88.101:47726 ESTABLISHED 1333/java
tcp6 0 0 192.168.88.104:3888 192.168.88.102:50104 ESTABLISHED 1333/java
tcp6 0 0 192.168.88.104:3888 192.168.88.103:58344 ESTABLISHED 1333/java
tcp6 0 0 192.168.88.104:48034 192.168.88.102:2888 ESTABLISHED 1333/java
通过上面的网络信息整体网络连接图如下

上图说明:
zookeeper Leader和Follower连接主要通过2888和3888,2888主要用于leader与follower进行工作,3888用于Leader选举。每个zookeeper节点都会与其他节点建立连接。
4.3.2 选举流程
情况一:第一次启动
以上面我们搭好的4台节点为例,myid和zxid情况如下:

| 节点名称 | myid | zxid |
|---|---|---|
| q101 | 4 | 0 |
| q102 | 3 | 0 |
| q103 | 2 | 0 |
| q104 | 1 | 0 |
选举前提当投票数量超过半数时才有效,此处4台节点,当第一次启动时候zxid都为0。只要有3台节点启动就可以选举出Leader。虽然说q101的myid=4但是如果最后启动q101,那么第一次启动时一定是q102成为Leader。
情况二:zxid不为0时,当集群重启,或Leader挂了的时候
当Leader挂了后,zookeeper集群会进行推选制选举,会优先选举数据最全的节点作为Leader(通过比较zxid,zxid越大代表该节点数据最全),如果zxid相同再比较myid。

| 节点名称 | myid | zxid |
|---|---|---|
| q101 | 4 | 0x100000009 |
| q103 | 2 | 0x100000010 |
| q104 | 1 | 0x100000010 |
原Leader q102挂掉后无论哪个节点先发现Leader挂掉,都会推选zxid最大的节点,q103和q104 zxid 都为xxx10再比较myid。所以此处q103最终会被选为新的Leader。
5 watch
- Watch是轻量级的,其实就是本地JVM的Callback,服务器端只是存了是否有设置了Watcher的布尔类型。
- 在服务端,在FinalRequestProcessor处理对应的Znode操作时,会根据客户端传递的watcher变量,添加到对应的ZKDatabase(org.apache.zookeeper.server.ZKDatabase)中进行持久化存储,同时将自己NIOServerCnxn做为一个Watcher callback,监听服务端事件变化
- Leader通过投票通过了某次Znode变化的请求后,然后通知对应的Follower,Follower根据自己内存中的zkDataBase信息,发送notification信息给zookeeper客户端。
- Zookeeper客户端接收到notification信息后,找到对应变化path的watcher列表,挨个进行触发回调。
6 zookeeper实现分布式锁
6.1 实现原理
多个节点同时在一个指定的节点下面创建临时会话顺序节点,谁创建的节点序号最小,谁就获得了锁,并且其他节点就会监听序号比自己小的节点,一旦序号比自己小的节点被删除了,其他节点就会得到相应的事件,然后查看自己是否为序号最小的节点,如果是,则获取锁。
