storage R&D guy.
全部博文(1000)
分类: 服务器与存储
2015-07-22 16:52:56
网上关于zookeeper 原理分析的文章很多, 但是客户端的使用分析还是较少。在使用zookeeper时我们难免会碰到一些问题,本文旨在从zookeeper 客户端使用的角度分享一些应用开发的经验,让大家少走一些弯路。
全文分为三个章节:
图1. 整体数据结构
zookeeper c 客户端主要围绕zhandler_t结构进行一系列操作,上图是一个全局性的展示,便于我们对其有个整体的了解。
重点关注其中4个队列:
to_process : 已经接收的网络数据包,准备进行处理;
to_send : 准备发送的网络数据包;
sent_requests : 异步操作时未完成的请求
completions_to_process : 已经完成的异步请求,准备执行(包括watcher回调)
图2. 整体流程
整体流程 包括:
main线程:各种zookeeper api, 在应用中进行调用,用来执行zookeeper节点文件的增、删、改、查(包括watcher、异步回调、acl的设置)
io线程:zookeeper_mt库才有,基于事件循环,进行网络通信;
completion线程:zookeeper_mt库才有,执行异步回调、watcher回调;
main thread即应用开发的主线程,调用各种zookeeper api。
首先要调用zookeeper_init:进行资源初始化(参数的默认设置、host打乱顺序),如果是zookeeper_mt库则启动两个线程:io线程、completion线程, 设置相关参数、线程间通信管道。
接着就是各种zookeeper节点操作api(eg:zoo_create), 完成应用程序预期的功能。
图3. io thread
如上图所示,io线程使用poll进行事件循环,处理网络数据包,并进行协议包的解析与封装。
图4. completion thread
completion线程的功能比较单一,就是从completion_to_process队列中取出数据进行回调函数的运行。
zookeeper c 客户端分别提供了单线程的库与多线程的库,分别叫zookeeper_st 和 zookeeper_mt。
zookeeper_st主要用于不支持pthread 或者支持不完善的系统环境, zookeeper_st只提供异步操作的api, 应用程序需要在自己的事件循环中,调用api进行相关操作。
zookeeper_mt 会启动两个独立线程:io线程与completion线程, 封装了内部的事件循环,分别提供了同步和异步的api, 一般情况下建议使用这个库。
zookeeper_st仅提供异步的api, zookeeper_mt提供同步与异步的api.
先说一下同步api, zookeeper_mt的同步:主线程调用完对应api后等待,io线程完成对应的操作后,通知主线程。
关于异步api, zookeeper_st,zookeeper_mt都提供,但是各自的调用方式不同。zookeeper_mt主线程执行完api调用后立即返回, completion线程完成回调函数的执行;但是zookeeper_st是单线程如果达到异步的效果呢?zookeeper_st提供了对应的事件处理函数: zookeeper_interest、zookeeper_process, 应用程序可以根据这两个api完成对应的事件循环,进行异步api的处理(可参见cli_st的实现)
图5.状态变迁
4 字节长度 + 数据包内容
握手请求包:prime_connection(zhandle_t *zh)
握手回应包:recv_buffer(zh->fd, zh->input_buffer);deserialize_prime_response
字段 | 长度(byte) | 描述 |
protocolVersion | 4 | 协议版本号 |
lastZxidSeen | 8 | 最后一次事务id |
timeOut | 4 | 超时时间(ms) |
sessionId | 8 | 会话id |
passwd_len | 4 | 密码长度 |
passwd | 16 | 密码 |
字段 | 长度(byte) | tag | 描述 |
xid | 4 | header | PING_XID -2 |
type | 4 | header | ZOO_PING_OP 11 |
auth请求包:send_auth_info、send_last_auth_info
字段 | 长度(byte) | tag | 描述 |
xid | 4 | header | AUTH_XID -4 |
type | 4 | header | ZOO_SETAUTH_OP 100 |
auth_type | 4 | req | 0(ignored by the server) |
scheme_len | 4 | req | schema长度 |
scheme | String | req | 具体schema字符串信息 |
auth_len | 4 | req | auth buffer的长度 |
auth | String | req | 具体auth字符串信息 |
auth回应包:deserialize_ReplyHeader
字段 | 长度(byte) | tag | 描述 |
xid | 4 | hdr | AUTH_XID -4 |
zxid | 8 | hdr | 事务id |
err | 4 | hdr | 返回信息,非0 出错 |
请求包:send_set_watches
字段 | 长度(byte) | tag | 描述 |
xid | 4 | header | SET_WATCHES_XID -8 |
type | 4 | header | ZOO_SETWATCHES_OP 101 |
relativeZxid | 8 | req | 关联的事务id |
dataWatches | Len 4 (vector个数)String | req | get_data watcher |
existWatches | Len 4 (vector个数)String | req | exist watcher |
childWatches | Len 4 (vector个数)String | req | get_children watcher |
回应包:deserialize_ReplyHeader
字段 | 长度(byte) | tag | 描述 |
xid | 4 | hdr | AUTH_XID -4 |
zxid | 8 | hdr | 事务id |
err | 4 | hdr | 返回信息,非0 出错 |
请求包:各个api, 例如zoo_acreate
字段 | 长度(byte) | tag | 描述 |
xid | 4 | header | 自定义xid(xid = time(0), xid++) |
type | 4 | header |
ZOO_CREATE_OP 1ZOO_DELETE_OP 2ZOO_EXISTS_OP 3
ZOO_GETDATA_OP 4 ZOO_SETDATA_OP 5 ZOO_GETACL_OP 6 ZOO_SETACL_OP 7 ZOO_GETCHILDREN_OP 8 ZOO_SYNC_OP 9 ZOO_GETCHILDREN2_OP 12 ZOO_CHECK_OP 13 ZOO_MULTI_OP 14 ZOO_CLOSE_OP -11 |
api_req |
不同的请求封装不同的包.eg: zoo_awgetchar* path
Int32_t watch |
req |
回应包:process_sync_completion、process_completions
字段 | 长度(byte) | tag | 描述 |
xid | 4 | hdr | AUTH_XID -4 |
zxid | 8 | hdr | 事务id |
err | 4 | hdr | 返回信息,非0 出错 |
api_res | 不同的请求封装不同的包.eg: zoo_awgetstruct buffer data;struct Stat stat; | reply |