Paxos 算法中的 zookeeper 代码解析
ZooKeeper 是近期比较热门的一个类 Paxos 实现。也是一个逐渐得到广泛应用的开源的分布
式锁服务实现。被认为是
Chubby 的开源版,虽然具体实现有很多差异。ZooKeeper 概要的介
绍可以看官方文档:
http://hadoop.apache.org/zookeeper 这里我们重点来看下它的内部实现。
ZooKeeper 集群中的每个 server 都要知道其他成员,通过在配置文件 zoo.cfg 中作如下配置
实现:
tickTime=2000
dataDir=/var/zookeeper/
clientPort=2181
initLimit=5
syncLimit=2
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888
其中第一个端口(端口
1)用来做运行期间 server 间的通信,第二个端口(端口 2)用来做
leader election,另外还有一个端口(端口 0)接收客户端请求。每个机器的这份文件都可以
相同。那么一台机器怎样确定自己是谁呢?通过
dataDir 目录下的 myid 文本文件确定。myid
文件只包含一个数字,内容就是所在
Server 的 ID:QuorumPeer.myid。
构成
Zookeeper 集群的所有节点,称作 ensemble。 增加 ensemble 中的投票节点数,可以提
高
Zookeeper 的 QPS,但是写入的效率会下降,因为每个写入操作要在至少过半的投票节
点达成一致。投票节点增加,完成投票的消息开销就会增加。为了解决这个问题,
Zookeeper
引入了一个新的节点类型:
Observer,与 follower 相比,只做投票之外的事情,不参与一
致性协议的达成。这样通过增加
Observer 节点即可以提高读吞吐量,又不影响写入的性能,
只是可靠性仍然与原先相同,由投票节点的个数决定。
ZooKeeper 的启动类是 org.apache.zookeeper.server.quorum.QuorumPeerMain 启动时传入配置
文件
zoo.cfg 的路径。QuorumPeerMain 解析各项配置,如果发现 server 列表只有一个,那么
直接通过
ZooKeeperServerMain 来启动单机版的 Server;如果有多个,那么读取 server 列表
和
myid 文件,启动 QuorumPeer 线程(QuorumPeer 继承了 Thread,以下直接以线程类作为
线程名称)。每个
QuorumPeer 线程启动之前都会先启动一个 cnxnFactory 线程,作为 nio
server 接受客户端请求。QuorumPeer 线程启动之后,首先做 leader election。一个 QuorumPeer
代表一个
ZooKeeper 节点,或者说一个 ZooKeeper 进程。QuorumPeer 共有 4 个状态:
LOOKING, FOLLOWING, LEADING, OBSERVING;启动时初始状态是 LOOKING,表示正
在寻找确定
leader 中。Leader election 的默认算法是基于 TCP 实现的 fast Paxos 算法,由
FastLeaderElection 实现。Leader election 的具体实现在淘宝核心系统团队已经有一篇 Blog 分