您的位置:首页 > 其它

zookeeper的watcher监听不到zk后续数据的变化问题

2016-06-02 17:08 2136 查看


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结构体定义如下:

struct String_vector

{

int32_t count;

char * *data;

};

Zookeeper API将getchildren结果通过String_vector结构体返回时,malloc分配内存,将子节点所有目录存放在data中,而释放内存需要有客户端来做处理。


问题解决:

调用zoo_get_children(zh, path, watch, strings);需要通过调用zookeper提供的释放内存的方法:deallocate_String_vector(strings)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  zk zookeeper watcher 异常