前言
ZooKeeper是一个相对简单的分布式协调服务,通过阅读源码我们能够更进一步的清楚分布式的原理。
环境
ZooKeeper 3.4.9
入口函数
在bin/zkCli.sh
中,我们看到client端的真实入口其实是一个org.apache.zookeeper.ZooKeeperMain
的Java类
"$JAVA" "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" \
-cp "$CLASSPATH" $CLIENT_JVMFLAGS $JVMFLAGS \
org.apache.zookeeper.ZooKeeperMain "$@"
通过源码走读,看到在ZooKeeperMain
中主要由两部分构成
connectToZK(cl.getOption("server"));
while ((line = (String)readLine.invoke(console, getPrompt())) != null) {
executeLine(line);
}
- 构造一个
ZooKeeper
对象,同ZooKeeperServer进行建立通信连接 - 通过反射调用
jline.ConsoleReader
类,对终端输入进行读取,然后通过解析单行命令,调用ZooKeeper
接口。
如上所述,client端其实是对 zookeeper.jar 的简单封装,在构造出一个ZooKeeper对象后,通过解析用户输入,调用 ZooKeeper 接口和 Server 进行交互。
ZooKeeper 类
刚才我们看到 client 端同 ZooKeeper Server 之间的交互其实是通过 ZooKeeper 对象进行的,接下来我们详细深入到 ZooKeeper 类中,看看其和服务端的交互逻辑。
public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher,
boolean canBeReadOnly)
throws IOException
{
ConnectStringParser connectStringParser = new ConnectStringParser(connectString);
HostProvider hostProvider = new StaticHostProvider( connectStringParser.getServerAddresses());
cnxn = new ClientCnxn(connectStringParser.getChrootPath(),
hostProvider, sessionTimeout, this, watchManager, getClientCnxnSocket(), canBeReadOnly);
cnxn.start();
}
在 ZooKeeper的构造方法中,可以看到 ZooKeeper 中使用 Server 的服务器地址构建了一个 ClientCnxn
类,在这个类中,系统新建了两个线程
sendThread = new SendThread(clientCnxnSocket);
eventThread = new EventThread();
其中,SendThread
负责将ZooKeeper
的请求信息封装成一个Packet
,发送给 Server ,并维持同Server的心跳,EventThread
负责解析通过通过SendThread
得到的Response
,之后发送给Watcher::processEvent
进行详细的事件处理。
如上图所示,Client中在终端输入指令后,会被封装成一个Request
请求,通过submitRequest