这段时间来,也在和公司里的一些同窗交流使用zk的心得,整理了一些常见的zookeeper问题。这个页面的目标是解答一些zk常见的使用问题,同时也让你们明确zk不能干什么。页面会一直更新。html
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点中的加大风险之处。更多关于客户端地址列表相关的,请查看文章《ZooKeeper客户端地址列表的随机原理》java
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)。git
3. 不一样的客户端对同一个节点是否能获取相同的数据github
4. 一个客户端修改了某个节点的数据,其它客户端可以立刻获取到这个最新数据吗apache
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().api
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,只会收到一次通知。即session
for( int i = 0; i < 3; i++ ){ zk.getData( path, true, null ); zk.getChildren( path, true ); }
f. Watcher对象只会保存在客户端,不会传递到服务端。运维
7.我可否收到每次节点变化的通知
若是节点数据的更新频率很高的话,不能。
缘由在于:当一次数据修改,通知客户端,客户端再次注册watch,在这个过程当中,可能数据已经发生了许屡次数据修改,所以,千万不要作这样的测试:"数据被修改了n次,必定会收到n次通知"来测试server是否正常工做。(我曾经就作过这样的傻事,发现Server一直工做不正常?其实不是)。即便你使用了GitHub上这个客户端也同样。
8.能为临时节点建立子节点吗
不能。
9. 是否能够拒绝单个IP对ZK的访问,操做
ZK自己不提供这样的功能,它仅仅提供了对单个IP的链接数的限制。你能够经过修改iptables来实现对单个ip的限制,固然,你也能够经过这样的方式来解决。https://issues.apache.org/jira/browse/ZOOKEEPER-1320
10. 在getChildren(String path, boolean watch)是注册了对节点子节点的变化,那么子节点的子节点变化能通知吗
不能
11.建立的临时节点何时会被删除,是链接一断就删除吗?延时是多少?
链接断了以后,ZK不会立刻移除临时数据,只有当SESSIONEXPIRED以后,才会把这个会话创建的临时数据移除。所以,用户须要谨慎设置Session_TimeOut
12. zookeeper是否支持动态进行机器扩容?若是目前不支持,那么要如何扩容呢?
截止2012-03-15,3.4.3版本的zookeeper,还不支持这个功能,在3.5.0版本开始,支持动态加机器了,期待下吧: https://issues.apache.org/jira/browse/ZOOKEEPER-107
13. ZooKeeper集群中个服务器之间是怎样通讯的?
Leader服务器会和每个Follower/Observer服务器都创建TCP链接,同时为每一个F/O都建立一个叫作LearnerHandler的实体。LearnerHandler主要负责Leader和F/O之间的网络通信,包括数据同步,请求转发和Proposal提议的投票等。Leader服务器保存了全部F/O的LearnerHandler。
14.zookeeper是否会自动进行日志清理?若是进行日志清理?
zk本身不会进行日志清理,须要运维人员进行日志清理,详细关于zk的日志清理,能够查看《ZooKeeper日志清理》