原创技术文章,转载请注明:转自http://newliferen.github.io/
ZooKeeper客户端代码相对简单,核心的类就是ZooKeeper、HostProvider、ClientCnxn、ClientCnxnSocketNIO这几个核心类。其中ZooKeeper是客户端接口类,为客户端提供各种操作访问zk的接口方法,HostProvider持有服务器连接端口等信息,应用程序通过创建ZooKeeper对象建立与zk server端的socket连接,ClientCnxnSocketNIO则向socket连接读写数据。
创建ZooKeeper对象时发生了什么
1 | public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, |
ClientCnxn构造器
1 | public ClientCnxn(String chrootPath, HostProvider hostProvider, int sessionTimeout, ZooKeeper zooKeeper, |
揭开ZooKeeper请求的神秘面纱
以创建节点为例,对zk客户端内部实现展开学习,在学习之前,一直在猜想zk server是如何处理客户端的watcher事件,以往的经验是发送消息,或者是在响应结果中进行回调,但是看了zk源码之后,发现zk采用了很聪明的方式处理watcher事件。每一次请求,只要是注册了watcher或者回调事件,在组织request请求对象时,都不会让watcher事件和request产生关联,并且watcher事件也不会随着request发送到zk server端,只是创建了Packet对象,将watcher事件的实现保存在Packet对象内部,在向zk server端发送请求后,将Packet对象保存到pendingQueue队列中。eventThread线程从pendingQueue队列中取出Packet对象后,封装成WatcheEvent进行回调,这样客户端的回调事件得到执行。
在整个请求过程中,可以看出ZooKeeper的实现一直在尽一切可能减少网络传输时占用带宽,提高请求响应效率,整个过程中回调事件对zk server端是透明的,回调对server端不产生任何压力,在高并发场景中server高可用性得到进一步保障。
- 创建节点入口方法
1 | public void create(final String path, byte data[], List<ACL> acl, |
- 请求对象入队
1 | Packet queuePacket(RequestHeader h, ReplyHeader r, Record request, |
- 触发发送请求
1 | clientCnxnSocket.doTransport(to, pendingQueue, outgoingQueue, ClientCnxn.this); |
- 发送请求阶段
真正要发送到zk server端的数据,就在createBB()方法中组织的。
1 | synchronized(outgoingQueue) { |
- 序列化request对象
1 | public void createBB() { |