最近要用到zookeeper,但是网上c版的资料太少,所以参考各个大神的博客,自己也写了一点使用方法,记录一下,顺便帮助初学者入门。
1. zookeeper简介
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,主要应用场景有(数据订阅/发布 ,负载均衡, 命名服务, 分布式协调/通知,集群管理,Master选举,分布式锁,分布式队列)。
2. 官网及编译
官网 http://zookeeper.apache.org/
我下载的版本是3.3.6
./configure --prefix=/usr/local/zookeeper3.3.6
make
sudo make install
sudo ldconfig
3. 常用api
这部分主要参考ztao大神的博客。
会话的建立
zhandle_t *zookeeper_init(const char *host, watcher_fn fn, int recv_timeout, const clientid_t *clientid, void *context, int flags);
host: 格式为host:port,用逗号分隔所有集群的主机列表
fn: 会话建立的回调函数。因为是异步的,所以也需要用回调函数来确认是否建立成功
recv_timeout: 会话超时时间,单位ms
clientid: 主要是用于会话恢复的时候使用,已经建立的会话可以使用zoo_clent_id获得,如果是新建会话将其置为NULL即可
content: 用户自定义的数据指针,需要的时候可以通过zoo_get_context返回。
flags: 保留,未使用,置0即可
监听回调
typedef void (*watcher_fn)(zhandle_t *zh, int type, int state, const char *path,void *watcherCtx);
zh: 会话建立的时候的句柄,只初始化一个句柄的时候没用
type: 事件类型,包括ZOO_CREATED_EVENT、ZOO_DELETED_EVENT、ZOO_CHANGED_EVENT、ZOO_CHILD_EVENT、ZOO_SESSION_EVENT
state: 表示session的状态,包括ZOO_CONNECTING_STATE、ZOO_CONNECTED_STATE等
path: 事件相关的path。创建连接的时候是SESSION_EVENT类型的事件,其值为NULL。
watcherCtx: 在会话创建的时候为NULL。在后续操作的时候为用户传进来的上下文信息。
创建znode节点
int zoo_acreate(zhandle_t *zh, const char *path, const char *value, int valuelen, const struct ACL_vector *acl, int flags, string_completion_t completion, const void *data);
zh: 会话句柄信息
path: 要创建的路径
value,valuelen: 节点的数据内容和长度,可以使用zoo_awget、zoo_set等接口读取访问和设置
acl: 主要是管理和安全需要的,对于可信环境而言,值可以设置为ZOO_OPEN_ACL_UNSAFE。这个参数不能传递空地址
flag: 创建节点时要附带的参数,包括ZOO_EPHEMERAL(临时)和ZOO_SEQUENCE(顺序)等
string_completion_t: 异步创建完成之后的回调函数
value: 回调函数的参数
完成回调
typedef void (*void_completion_t)(int rc, const void *data);
typedef void (*string_completion_t)(int rc, const char *value, const void *data);
typedef void (*strings_completion_t)(int rc, const struct String_vector *strings, const void *data);
typedef void (*data_completion_t)(int rc, const char *value, int value_len, const struct Stat *stat, const void *data);
上面是几个常用的回调函数的原型,会在很多地方被用到。
rc 是返回码,其值可以参照enum ZOO_ERRORS,正常情况下用ZOK表示成功返回,不过在ZCONNECTIONLOSS和ZOPERATIONTIMEOUT这类异常发生的时候,也会触发会话事件的函数被回调。对于非正常情况的错误通常会进行重试操作等响应方式,当然需要在使用的时候甄别对待了。
而其他的版本,基本都是将当初设置的参数再透传过来,供回调函数里面使用(包括重试之前的操作),常用手法了,此处不表。
获取节点数据和监听节点
这里是ZooKeeper工作的重要部分,通过get的方式可以获取特定节点存储的数据信息和子节点信息,同时通过设置watch可以对数据或者节点的变更、异常做出最快的响应。
获取数据一般有zoo_awget和zoo_awget_children两类,主要是获取节点本身所存储的数据,以及某个路径下所有的子节点信息,两者的回调函数不同:
zoo_awget的回调函数类型是data_completion_t,其返回的数据存储在value指向的内存当中;
而zoo_awget_children的回调函数类型是strings_completion_t,其返回的数据(子节点信息)存储在一个String_vector的自定义数据结构当中。
上面的struct String_vector是一个简单的字符串数组的封装,count域表明内容的个数,data域为一些列的指针数组,我们见到传递过来的是一个const指针,如果后面自己额外申请了这个结构,就需要记得在使用完后使用free_vector进行内存的释放。
4. 例子
例子在github上,写了cmake。
地址:https://github.com/xixihahag/zookeeper_example