background image

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 分