zookeeper的watcher监听不到zk后续数据的变化问题
1 watcher函数原型 24 void watcher(zhandle_t *zzh, int type, int state, const char *path, void *watcherCtx)1.1 Watch事件类型(type) ZOO_CREATED_EVENT(value=1):节点创建事件,需要watch一个不存在的节点,当节点被创建时触发,此watch
1 watcher函数原型 24 void watcher(zhandle_t *zzh, int type, int state, const char *path, void *watcherCtx)
1.1 Watch事件类型(type)
ZOO_CREATED_EVENT(value=1):节点创建事件,需要watch一个不存在的节点,当节点被创建时触发,此watch通过zoo_exists()设置
ZOO_DELETED_EVENT(value=2):节点删除事件,此watch通过zoo_exists()或zoo_get()设置
ZOO_CHANGED_EVENT(value=3):节点数据改变事件,此watch通过zoo_exists()或zoo_get()设置
ZOO_CHILD_EVENT(value=4):子节点列表改变事件,此watch通过zoo_get_children()或zoo_get_children2()设置
ZOO_SESSION_EVENT(value=-1):会话事件,客户端与服务端断开或重连时触发
ZOO_NOTWATCHING_EVENT(value=-2):watch移除事件,服务端出于某些原因不再为客户端watch节点时触发
1.2 watcher事件状态(state)
state=-112 会话超时状态 ZOO_EXPIRED_SESSION_STATE
state= -113 认证失败状态 ZOO_AUTH_FAILED_STATE
state= 1 连接建立中 ZOO_CONNECTING_STATE
state= 2 (暂时不清楚如何理解这个状态,ZOO_ASSOCIATING_STATE)
state=3 连接已建立状态 ZOO_CONNECTED_STATE
state= 999 无连接状态
2 watcher的原理
在zookeeper_init中设置watcher,当zookeeper client与server会话建立后,触发watcher,当 watcher 的state = 3 (ZOO_CONNECTED_STATE), type = -1(ZOO_SESSION_EVENT)时,确认 会话成功建立,此时zookeeper client 初始化成功,可进行后续操作。
当watcher链接不上zk后,watcher会收到一次type=-1,state=1的事件,直到watcher能连上zk后,watcher会收到一次type=ZOO_SESSION_EVENT,state=ZOO_EXPIRED_SESSION_STATE的事件,如果确认能连上,则watcher会再次收到一次type=-1(ZOO_SESSION_EVENT),state=3(ZOO_CONNECTED_STATE)的事件。
3 watcher监听不到zk后续数据的解决方法
根据watcher的原理得知,如果watcher检测不到zk的数据变化时,肯定是因为watcher连接失败后, 没有重新注册watcher,解决方法很简单,也就是当type=ZOO_SESSION_EVENT,同时state=ZOO_EXPIRED_SESSION_STATE时,重新注册下watcher即可。
4 其他问题
4.1 关于zookeeper_init函数的使用
问题描述:
开发人员在调用zookeeper_init函数时,若返回一个非空句柄zhandle_t *zh,则认为初始化成功,这样可能会导致后续操作失败。
问题分析:
zhandle_t *zookeeper_init(const char *host, watcher_fn fn, int recv_timeout,const clientid_t *clientid, void *context, int flags) 函 数 返回一个zookeeper客户端与服务器通信的句柄,通常我们仅仅根据返回句柄情况来判断zookeeper 客户端与zookeeper服务器是否 建立连接。如果句柄为空则认为是失败,非空则成功。其实不然,zookeeper_init创建与ZooKeeper服务端通信的句柄以及对应于此句柄的会话,而会话的创建是一个异步的过程,仅当会话建立成功,zookeeper_init才返回一个可用句柄。
问题解决:
如何正确判断zookeepr_init初始化成功,可通过以下三种方式
1、判断句柄的state是否为ZOO_CONNECTED_STATE状态,通过zoo_state(zh)判断状态值是否为ZOO_CONNECTED_STATE。
2、 在zookeeper_init中设置watcher,当zookeeper client与server会话建立后,触发watcher,当 watcher 的state = 3 (ZOO_CONNECTED_STATE), type = -1(ZOO_SESSION_EVENT)时,确认 会话成功建立,此时zookeeper client 初始化成功,可进行后续操作。
3、业务上可以做保证,调用zookeeper_init返回句柄zh,通过该句柄尝试做zoo_exists()或zoo_get_data()等操作,根据操作结果来判断是否初始化成功。
4.2 zoo_get_children内存泄露问题
问题描述:
调用zoo_get_children函数出现内存泄露问题。
问题分析:
通过查看代码发现问题在于 ZOOAPI int zoo_get_children(zhandle_t *zh, const char *path, int watch,struct String_vector *strings), 该API中String_vector *strings结构体定义如下:
Zookeeper API将getchildren结果通过String_vector结构体返回时,malloc分配内存,将子节点所有目录存放在data中,而释放内存需要有客户端来做处理。
问题解决:
调用zoo_get_children(zh, path, watch, strings);需要通过调用zookeper提供的释放内存的方法:deallocate_String_vector(strings)。
更多推荐
所有评论(0)