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

1 watcher函数原型

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)
--------------------- 
原文:https://blog.csdn.net/emeitu/article/details/51568548 

猜你喜欢

转载自blog.csdn.net/yangyangye/article/details/86288230