IT技术博客大学习 共学习 共进步

ZooKeeper FAQ

淘宝网通用产品团队博客 2011-12-22 22:16:50 浏览 3,882 次

     这段时间来,也在和公司里的一些同学交流使用zk的心得,整理了一些常见的zookeeper问题。这个页面的目标是解答一些zk常见的使用问题,同时也让大家明确zk不能干什么。页面会一直更新。

客户端

    1. 客户端对ServerList的轮询机制是什么

     随机,客户端在初始化( new ZooKeeper(String connectString, int sessionTimeout, Watcher watcher) )的过程中,将所有Server保存在一个List中,然后随机打散,形成一个环。之后从0号位开始一个一个使用。

     两个注意点:1. Server地址能够重复配置,这样能够弥补客户端无法设置Server权重的缺陷,但是也会加大风险。(比如: 192.168.1.1:2181,192.168.1.1:2181,192.168.1.2:2181). 2. 如果客户端在进行Server切换过程中耗时过长,那么将会收到SESSION_EXPIRED. 这也是上面第1点中的加大风险之处。

    2.客户端如何正确处理CONNECTIONLOSS(连接断开) 和 SESSIONEXPIRED(Session 过期)两类连接异常

     在ZooKeeper中,服务器和客户端之间维持的是一个长连接,在 SESSION_TIMEOUT 时间内,服务器会确定客户端是否正常连接(客户端会定时向服务器发送heart_beat),服务器重置下次SESSION_TIMEOUT时间。因此,在正常情况下,Session一直有效,并且zk集群所有机器上都保存这个Session信息。在出现问题情况下,客户端与服务器之间连接断了(客户端所连接的那台zk机器挂了,或是其它原因的网络闪断),这个时候客户端会主动在地址列表(初始化的时候传入构造方法的那个参数connectString)中选择新的地址进行连接。

     好了,上面基本就是服务器与客户端之间维持长连接的过程了。在这个过程中,用户可能会看到两类客异常CONNECTIONLOSS(连接断开) 和SESSIONEXPIRED(Session 过期)。

     CONNECTIONLOSS发生在上面红色文字部分,应用在进行操作A时,发生了CONNECTIONLOSS,此时用户不需要关心我的会话是否可用,应用所要做的就是等待客户端帮我们自动连接上新的zk机器,一旦成功连接上新的zk机器后,确认刚刚的操作A是否执行成功了。

     SESSIONEXPIRED发生在上面蓝色文字部分,这个通常是zk客户端与服务器的连接断了,试图连接上新的zk机器,这个过程如果耗时过长,超过 SESSION_TIMEOUT 后还没有成功连接上服务器,那么服务器认为这个session已经结束了(服务器无法确认是因为其它异常原因还是客户端主动结束会话),开始清除和这个会话有关的信息,包括这个会话创建的临时节点和注册的Watcher。在这之后,客户端重新连接上了服务器在,但是很不幸,服务器会告诉客户端SESSIONEXPIRED。此时客户端要做的事情就看应用的复杂情况了,总之,要重新实例zookeeper对象,重新操作所有临时数据(包括临时节点和注册Watcher)。

    3. 不同的客户端对同一个节点是否能获取相同的数据

    4. 一个客户端修改了某个节点的数据,其它客户端能够马上获取到这个最新数据吗

     ZooKeeper不能确保任何客户端能够获取(即Read Request)到一样的数据,除非客户端自己要求:方法是客户端在获取数据之前调用org.apache.zookeeper.AsyncCallback.VoidCallback, java.lang.Object) sync.

     通常情况下(这里所说的通常情况满足:1. 对获取的数据是否是最新版本不敏感,2. 一个客户端修改了数据,其它客户端需要不需要立即能够获取最新),可以不关心这点。

     在其它情况下,最清晰的场景是这样:ZK客户端A对 /my_test 的内容从 v1->v2, 但是ZK客户端B对 /my_test 的内容获取,依然得到的是 v1. 请注意,这个是实际存在的现象,当然延时很短。解决的方法是客户端B先调用 sync(), 再调用 getData().

    5. ZK为什么不提供一个永久性的Watcher注册机制

     不支持用持久Watcher的原因很简单,ZK无法保证性能。

     6. 使用watch需要注意的几点

     a. Watches通知是一次性的,必须重复注册.

     b. 发生CONNECTIONLOSS之后,只要在session_timeout之内再次连接上(即不发生SESSIONEXPIRED),那么这个连接注册的watches依然在。

     c. 节点数据的版本变化会触发NodeDataChanged,注意,这里特意说明了是版本变化。存在这样的情况,只要成功执行了setData()方法,无论内容是否和之前一致,都会触发NodeDataChanged。

     d. 对某个节点注册了watch,但是节点被删除了,那么注册在这个节点上的watches都会被移除。

     e. 同一个zk客户端对某一个节点注册相同的watch,只会收到一次通知。即

for( int i = 0; i < 3; i++ ){
    zk.getData( path, true, null );
    zk.getChildren( path, true );
}

    7.我能否收到每次节点变化的通知

     如果节点数据的更新频率很高的话,不能。

     原因在于:当一次数据修改,通知客户端,客户端再次注册watch,在这个过程中,可能数据已经发生了许多次数据修改,因此,千万不要做这样的测试:”数据被修改了n次,一定会收到n次通知”来测试server是否正常工作。(我曾经就做过这样的傻事,发现Server一直工作不正常?其实不是)。即使你使用了GitHub上这个客户端也一样。

    8.能为临时节点创建子节点吗

     不能。

    9. 是否可以拒绝单个IP对ZK的访问,操作

    ZK本身不提供这样的功能,它仅仅提供了对单个IP的连接数的限制。你可以通过修改iptables来实现对单个ip的限制,当然,你也可以通过这样的方式来解决。

    10. 在getChildren(String path, boolean watch)是注册了对节点子节点的变化,那么子节点的子节点变化能通知吗

    不能

    11.创建的临时节点什么时候会被删除,是连接一断就删除吗?延时是多少?

    连接断了之后,ZK不会马上移除临时数据,只有当SESSIONEXPIRED之后,才会把这个会话建立的临时数据移除。因此,用户需要谨慎设置Session_TimeOut

建议继续学习

  1. Zookeeper工作原理 (阅读 11,942)
  2. Zookeeper研究和应用 (阅读 9,341)
  3. ZooKeeper典型使用场景一览 (阅读 6,382)
  4. ZooKeeper管理员指南——部署与管理ZooKeeper (阅读 6,302)
  5. zookeeper使用和原理探究(一) (阅读 5,403)
  6. ZooKeeper解惑 (阅读 4,623)
  7. ZooKeeper权限控制初探 (阅读 3,661)
  8. ZooKeeper编程指导 (阅读 2,923)
  9. 10分钟看懂!基于Zookeeper的分布式锁 (阅读 2,482)