救火队长 阅读(95) 评论(0)

     了解ZooKeeper客户端的实现,对于使用ZooKeeper的客户端非常重要。 通过对客户端源码的阅读,了解了如下信息:

     创建ZooKeeper对象时,应会创建一个ClientCnxn(代表了客户端连接对象)。与此同时启动了两个线程:SendThread、EventThread。两个队列:outgoingQueue和pendingQueue。

        

 

同步调用:

         同步调用,就是客户端成功发送请求后,才继续执行。例如:zk.create(path,data,acl,createMode);

         这行代码会发起一个同步调用。一个线程A执行这个create时,会创建一个表示create动作的packet,放到数据发送队列outgoingQueue。之后当线程A就开始等待,直到SendThread线程从outgoingQueue队列取出该packet,并将其成功发送(已收到服务端的回应为准)。然后线程A才继续执行。

 

异步调用:

         异步调用,就是客户端不会管请求是否发送成功,都会继续执行。例如:zk.create(path,data,acl,createMode,stringCallback);

         这行代码会发起一个异步调用。一个线程A执行这个create时,会创建一个表示create动作的packet,放到数据发送队列outgoingQueue。线程A接着就去执行下一行代码了,而不会去管数据packet是否由SendThread线程发送到服务端了。

 

 

SendThread的职责:

1:创建一个长连接,用于会话保持

     通过周期性的发送ping packet到当前连接的ZooKeeper服务器实例。这个过程,我们通常称为心跳。每当客户端与服务端的连接断开后,会自动重新连接到下一个服务器。如果断开的是最后与一个服务器的连接,那么会重新连接到第一个服务器。

2:使用这个长连接与服务器通信

     1)发送客户调用

     不断的从outgoingQueue取出packet发给服务端。当发送的是Client的同步调用的packet,则在发送packet后,立即通知客户端同步调用线程继续执行。当发送的是Client的异步调用,则会将packet发给服务端,并保存到pendingQueue。当从服务端发回响应后,生成一个packet 完成事件交给EventThread,由Event执行CallBack调用。

2)处理服务端响应

     对服务端响应反序列化后,根据响应分类进行处理如下:

     · Ping的响应:不做处理

     · 认证失败的响应:创建认证失败的WatchedEvent,并将event交给EventThread处理。

     · 服务端的数据变更通知:生成相应的数据变更WatchedEvent,并将event交给EventThread处理。

     · 服务端对调用的回应:不论是同步调用还是异步调用,服务端都会给出回应。收到此类回应后,先是将watcher放到watcherManager中。然后对同步、异步做后续处理。

              如果是同步调用,则通知发起调用的线程继续处理。

              如果是异步调用,则将该packet交由EventThread来处理。例如对create、delete、exists、getData、getChildren方法调用的响应。

 

EventThread做了什么事呢?

 

     从上述描述中,也可以看出EventThread用于对接收到的packet或者event进行处理:

     · 如果是event,则从WatcherManager中取出相应的Watcher进行处理。

     · 如果是packet,则执行相关联的AsyncCallback。

 

通过源码的阅读,知道在使用ZooKeeper客户端时要注意以下两点:

        · 在进行Watcher回调时,会从WatchManager取出与相关path关联的多个Watcher(此时WatchManager中就不会再有这个path相关的Watcher了),然后串行的调用这多个Watcher#process方法。所以在编程时,会根据业务的需要,有可能会反复注册Watcher。

        · 另外因为多个Watcher的调用是串行的,所以不要因为一个Watcher的处理逻辑影响了整个客户端的Watcher回调。