Zookeeper C API 指南
以前自己的博客中轉(zhuǎn)載、翻譯或?qū)戇^(guò)(不過(guò)自己才疏學(xué)淺,寫(xiě)的不好)一些 Zookeeper 方面的文章,但是都沒(méi)有涉及到 Zookeeper C API 的內(nèi)容,今天的這篇博客是我農(nóng)歷新年的第一篇技術(shù)博客,我想詳細(xì)講講 Zookeeper C API 的使用規(guī)則和示例,算是把以前的舊帳還上吧 :-)
Zookeeper 官方頁(yè)面上提供了一些編程指南和 API 文檔,不過(guò)大部分都是 Java 示例,涉及 C API 的部分很少,只有在 ZooKeeper Programmer's Guide 中 ACL Permissions 一節(jié)講了 Zookeeper C API 中設(shè)置 ACL 應(yīng)該注意的事項(xiàng),正是由于缺少Zookeeper C API 相關(guān)的資料,大部分 Zookeeper C/C++ 開(kāi)發(fā)者只能通過(guò)閱讀 Zookeeper C API 的源碼來(lái)了解 C API 的使用方法,本文希望在此方面給大家提供一些便利,減少 Zookeeper 新手使用 C API 的困難和恐懼,當(dāng)然我自己也是一枚新手啦 :-)。
廢話不多說(shuō)了,先從最基本的開(kāi)始吧!
Zookeeper 偽分布式安裝
首先是 Zookeeper 的安裝,如果你沒(méi)有足夠的機(jī)器,建議在單機(jī)上通過(guò)偽分布式安裝方法來(lái)模擬 Zookeeper 集群,我在這里提供給大家一個(gè)簡(jiǎn)單的安裝包來(lái)降低偽分布式 Zookeeper 的安裝難度,該安裝包可以模擬一個(gè) 5 Zookeeper 實(shí)例的集群。下載zookeeper-3.4.0-pseudoclusters.tar.bz2,解壓至 /tmp/ 目錄(注意,安裝包里面 dataDir 和 dataLogDir 配置已經(jīng)預(yù)設(shè)為 /tmp/ 目錄,如果你只是自己在 Zookeeper 上做一些小實(shí)驗(yàn),建議不要更改該配置,這樣在你做完了實(shí)驗(yàn)以后刪除 /tmp/zookeeper/ 目錄即可),操作方法如下:
forhappy@haiping-ict:/tmp$ pwd /tmp forhappy@haiping-ict:/tmp$ tar xvf zookeeper-3.4.0-pseudoclusters.tar.bz2 forhappy@haiping-ict:/tmp$ cd zookeeper/ forhappy@haiping-ict:/tmp/zookeeper$ ls server001 server003 server005 stopZKCluster.sh server002 server004 startZKCluster.sh然后在 /tmp/zookeeper 目錄下執(zhí)行 startZKCluster.sh 啟動(dòng) Zookeeper 服務(wù),或者執(zhí)行 stopZKCluster.sh 停掉 Zookeeper 服務(wù)。
啟動(dòng) Zookeeper 服務(wù):
forhappy@haiping-ict:/tmp/zookeeper$ ./startZKCluster.sh . starting zookeeper instance server001... JMX enabled by default Using config: /tmp/zookeeper/server001/zookeeper-3.4.0/bin/../conf/zoo.cfg Starting zookeeper ... STARTED starting zookeeper instance server002... JMX enabled by default Using config: /tmp/zookeeper/server002/zookeeper-3.4.0/bin/../conf/zoo.cfg Starting zookeeper ... STARTED starting zookeeper instance server003... JMX enabled by default Using config: /tmp/zookeeper/server003/zookeeper-3.4.0/bin/../conf/zoo.cfg Starting zookeeper ... STARTED starting zookeeper instance server004... JMX enabled by default Using config: /tmp/zookeeper/server004/zookeeper-3.4.0/bin/../conf/zoo.cfg Starting zookeeper ... STARTED starting zookeeper instance server005... JMX enabled by default Using config: /tmp/zookeeper/server005/zookeeper-3.4.0/bin/../conf/zoo.cfg Starting zookeeper ... STARTED停掉 Zookeeper 服務(wù):
forhappy@haiping-ict:/tmp/zookeeper$ ./stopZKCluster.sh . stopping zookeeper instance server001... JMX enabled by default Using config: /tmp/zookeeper/server001/zookeeper-3.4.0/bin/../conf/zoo.cfg Stopping zookeeper ... STOPPED stopping zookeeper instance server002... JMX enabled by default Using config: /tmp/zookeeper/server002/zookeeper-3.4.0/bin/../conf/zoo.cfg Stopping zookeeper ... STOPPED stopping zookeeper instance server003... JMX enabled by default Using config: /tmp/zookeeper/server003/zookeeper-3.4.0/bin/../conf/zoo.cfg Stopping zookeeper ... STOPPED stopping zookeeper instance server004... JMX enabled by default Using config: /tmp/zookeeper/server004/zookeeper-3.4.0/bin/../conf/zoo.cfg Stopping zookeeper ... STOPPED stopping zookeeper instance server005... JMX enabled by default Using config: /tmp/zookeeper/server005/zookeeper-3.4.0/bin/../conf/zoo.cfg Stopping zookeeper ... STOPPEDZookeeper C API 安裝
Zookeeper C client 的實(shí)現(xiàn)在 src/c 目錄下,進(jìn)入到該目錄安裝 Zookeeper C client,步驟如下:
$ ./configure $ make $ sudo make install至此,基本的準(zhǔn)備工作已經(jīng)完成,你可以通過(guò) Zookeeper 本身提供的 Shell 來(lái)操作 Zookeeper,操作方法如下,進(jìn)入 /tmp/zookeeper/server001/zookeeper-3.4.0 目錄,執(zhí)行bin/zkCli.sh -server 127.0.0.1:2181 進(jìn)入 Zookeeper shell:
forhappy@haiping-ict:/tmp/zookeeper/server001/zookeeper-3.4.0$ bin/zkCli.sh -server 127.0.0.1:2181 [zk: 127.0.0.1:2181(CONNECTED) 2] help ZooKeeper -server host:port cmd argsconnect host:portget path [watch]ls path [watch]set path data [version]rmr pathdelquota [-n|-b] pathquit printwatches on|offcreate [-s] [-e] path data aclstat path [watch]close ls2 path [watch]history listquota pathsetAcl path aclgetAcl pathsync pathredo cmdnoaddauth scheme authdelete path [version]setquota -n|-b val path在 shell 中你可以完成基本的操作,如創(chuàng)建、獲取、刪除、設(shè)置某一節(jié)點(diǎn),設(shè)置節(jié)點(diǎn) ACL等,可以 zookeeper shell 中通過(guò) help 獲取相關(guān)命令的用法。
如果你按照上面的步驟完成了 Zookeeper 偽分布式的安裝,并且想繼續(xù)了解 Zookeeper C API 的使用方法,請(qǐng)繼續(xù)閱讀《Zookeeper C API 指南二(監(jiān)視(Wathes), 基本常量和結(jié)構(gòu)體介紹)》
接上一篇《Zookeeper C API 指南一(準(zhǔn)備工作)》,本問(wèn)將重點(diǎn)介紹 Zookeeper 監(jiān)視(Watches),以及 Zookeeper C API 中基本的常量與結(jié)構(gòu)體。
Zookeeper 監(jiān)視(Watches) 簡(jiǎn)介
Zookeeper C API 的聲明和描述在 include/zookeeper.h 中可以找到,另外大部分的 Zookeeper C API 常量、結(jié)構(gòu)體聲明也在 zookeeper.h 中,如果如果你在使用 C API 是遇到不明白的地方,最好看看 zookeeper.h,或者自己使用 doxygen 生成 Zookeeper C API 的幫助文檔。
Zookeeper 中最有特色且最不容易理解的是監(jiān)視(Watches)。Zookeeper 所有的讀操作——getData(),getChildren(), 和 exists() 都 可以設(shè)置監(jiān)視(watch),監(jiān)視事件可以理解為一次性的觸發(fā)器, 官方定義如下: a watch event is one-time trigger, sent to the client that set the watch, which occurs when the data for which the watch was set changes。對(duì)此需要作出如下理解:
-
(一次性觸發(fā))One-time trigger
當(dāng)設(shè)置監(jiān)視的數(shù)據(jù)發(fā)生改變時(shí),該監(jiān)視事件會(huì)被發(fā)送到客戶端,例如,如果客戶端調(diào)用了 getData("/znode1", true) 并且稍后 /znode1 節(jié)點(diǎn)上的數(shù)據(jù)發(fā)生了改變或者被刪除了,客戶端將會(huì)獲取到 /znode1 發(fā)生變化的監(jiān)視事件,而如果 /znode1 再一次發(fā)生了變化,除非客戶端再次對(duì) /znode1 設(shè)置監(jiān)視,否則客戶端不會(huì)收到事件通知。
-
(發(fā)送至客戶端)Sent to the client
Zookeeper 客戶端和服務(wù)端是通過(guò) socket 進(jìn)行通信的,由于網(wǎng)絡(luò)存在故障,所以監(jiān)視事件很有可能不會(huì)成功地到達(dá)客戶端,監(jiān)視事件是異步發(fā)送至監(jiān)視者的,Zookeeper 本身提供了保序性(ordering guarantee):即客戶端只有首先看到了監(jiān)視事件后,才會(huì)感知到它所設(shè)置監(jiān)視的 znode 發(fā)生了變化(a client will never see a change for which it has set a watch until it first sees the watch event). 網(wǎng)絡(luò)延遲或者其他因素可能導(dǎo)致不同的客戶端在不同的時(shí)刻感知某一監(jiān)視事件,但是不同的客戶端所看到的一切具有一致的順序。
-
(被設(shè)置 watch 的數(shù)據(jù))The data for which the watch was set
這意味著 znode 節(jié)點(diǎn)本身具有不同的改變方式。你也可以想象 Zookeeper 維護(hù)了兩條監(jiān)視鏈表:數(shù)據(jù)監(jiān)視和子節(jié)點(diǎn)監(jiān)視(data watches and child watches) getData() and exists() 設(shè)置數(shù)據(jù)監(jiān)視,getChildren() 設(shè)置子節(jié)點(diǎn)監(jiān)視。 或者,你也可以想象 Zookeeper 設(shè)置的不同監(jiān)視返回不同的數(shù)據(jù),getData() 和 exists() 返回 znode 節(jié)點(diǎn)的相關(guān)信息,而 getChildren() 返回子節(jié)點(diǎn)列表。因此, setData() 會(huì)觸發(fā)設(shè)置在某一節(jié)點(diǎn)上所設(shè)置的數(shù)據(jù)監(jiān)視(假定數(shù)據(jù)設(shè)置成功),而一次成功的 create() 操作則會(huì)出發(fā)當(dāng)前節(jié)點(diǎn)上所設(shè)置的數(shù)據(jù)監(jiān)視以及父節(jié)點(diǎn)的子節(jié)點(diǎn)監(jiān)視。一次成功的 delete() 操作將會(huì)觸發(fā)當(dāng)前節(jié)點(diǎn)的數(shù)據(jù)監(jiān)視和子節(jié)點(diǎn)監(jiān)視事件,同時(shí)也會(huì)觸發(fā)該節(jié)點(diǎn)父節(jié)點(diǎn)的child watch。
Zookeeper 中的監(jiān)視是輕量級(jí)的,因此容易設(shè)置、維護(hù)和分發(fā)。當(dāng)客戶端與 Zookeeper 服務(wù)器端失去聯(lián)系時(shí),客戶端并不會(huì)收到監(jiān)視事件的通知,只有當(dāng)客戶端重新連接后,若在必要的情況下,以前注冊(cè)的監(jiān)視會(huì)重新被注冊(cè)并觸發(fā),對(duì)于開(kāi)發(fā)人員來(lái)說(shuō) 這通常是透明的。只有一種情況會(huì)導(dǎo)致監(jiān)視事件的丟失,即:通過(guò) exists() 設(shè)置了某個(gè) znode 節(jié)點(diǎn)的監(jiān)視,但是如果某個(gè)客戶端在此 znode 節(jié)點(diǎn)被創(chuàng)建和刪除的時(shí)間間隔內(nèi)與 zookeeper 服務(wù)器失去了聯(lián)系,該客戶端即使稍后重新連接 zookeeper服務(wù)器后也得不到事件通知。
Zookeeper C API 常量與部分結(jié)構(gòu)(struct)介紹
與 ACL 相關(guān)的結(jié)構(gòu)與常量:
struct Id 結(jié)構(gòu)為:
struct Id {char * scheme;char * id; };struct ACL 結(jié)構(gòu)為:
struct ACL {int32_t perms;struct Id id; };struct ACL_vector 結(jié)構(gòu)為:
struct ACL_vector {int32_t count;struct ACL *data;};與 znode 訪問(wèn)權(quán)限有關(guān)的常量
-
const int ZOO_PERM_READ; //允許客戶端讀取 znode 節(jié)點(diǎn)的值以及子節(jié)點(diǎn)列表。
-
const int ZOO_PERM_WRITE;// 允許客戶端設(shè)置 znode 節(jié)點(diǎn)的值。
-
const int ZOO_PERM_CREATE; //允許客戶端在該 znode 節(jié)點(diǎn)下創(chuàng)建子節(jié)點(diǎn)。
-
const int ZOO_PERM_DELETE;//允許客戶端刪除子節(jié)點(diǎn)。
-
const int ZOO_PERM_ADMIN; //允許客戶端執(zhí)行 set_acl()。
-
const int ZOO_PERM_ALL;//允許客戶端執(zhí)行所有操作,等價(jià)與上述所有標(biāo)志的或(OR) 。
與 ACL IDs 相關(guān)的常量
-
struct Id ZOO_ANYONE_ID_UNSAFE; //(‘world’,’anyone’)
-
struct Id ZOO_AUTH_IDS;// (‘a(chǎn)uth’,’’)
三種標(biāo)準(zhǔn)的 ACL
-
struct ACL_vector ZOO_OPEN_ACL_UNSAFE; //(ZOO_PERM_ALL,ZOO_ANYONE_ID_UNSAFE)
-
struct ACL_vector ZOO_READ_ACL_UNSAFE;// (ZOO_PERM_READ, ZOO_ANYONE_ID_UNSAFE)
-
struct ACL_vector ZOO_CREATOR_ALL_ACL; //(ZOO_PERM_ALL,ZOO_AUTH_IDS)
與 Interest 相關(guān)的常量:ZOOKEEPER_WRITE, ZOOKEEPER_READ
這 兩個(gè)常量用于標(biāo)識(shí)感興趣的事件并通知 zookeeper 發(fā)生了哪些事件。Interest 常量可以進(jìn)行組合或(OR)來(lái)標(biāo)識(shí)多種興趣(multiple interests: write, read),這兩個(gè)常量一般用于 zookeeper_interest() 和 zookeeper_process()兩個(gè)函數(shù)中。
與節(jié)點(diǎn)創(chuàng)建相關(guān)的常量:ZOO_EPHEMERAL,?ZOO_SEQUENCE
zoo_create 函數(shù)標(biāo)志,ZOO_EPHEMERAL 用來(lái)標(biāo)識(shí)創(chuàng)建臨時(shí)節(jié)點(diǎn),ZOO_SEQUENCE 用來(lái)標(biāo)識(shí)節(jié)點(diǎn)命名具有遞增的后綴序號(hào)(一般是節(jié)點(diǎn)名稱后填充 10 位字符的序號(hào),如 /xyz0000000000, /xyz0000000001, /xyz0000000002, ...),同樣地,ZOO_EPHEMERAL,?ZOO_SEQUENCE可以組合。
與連接狀態(tài) Stat 相關(guān)的常量
以下常量均與 Zookeeper 連接狀態(tài)有關(guān),他們通常用作監(jiān)視器回調(diào)函數(shù)的參數(shù)。
| ZOOAPI const int? | ZOO_EXPIRED_SESSION_STATE |
| ZOOAPI const int? | ZOO_AUTH_FAILED_STATE |
| ZOOAPI const int? | ZOO_CONNECTING_STATE |
| ZOOAPI const int? | ZOO_ASSOCIATING_STATE |
| ZOOAPI const int? | ZOO_CONNECTED_STATE |
與監(jiān)視類型(Watch Types)相關(guān)的常量
以下常量標(biāo)識(shí)監(jiān)視事件的類型,他們通常用作監(jiān)視器回調(diào)函數(shù)的第一個(gè)參數(shù)。
- ZOO_CREATED_EVENT; // 節(jié)點(diǎn)被創(chuàng)建(此前該節(jié)點(diǎn)不存在),通過(guò) zoo_exists() 設(shè)置監(jiān)視。
- ZOO_DELETED_EVENT; // 節(jié)點(diǎn)被刪除,通過(guò) zoo_exists() 和 zoo_get() 設(shè)置監(jiān)視。
- ZOO_CHANGED_EVENT; // 節(jié)點(diǎn)發(fā)生變化,通過(guò) zoo_exists() 和 zoo_get() 設(shè)置監(jiān)視。
- ZOO_CHILD_EVENT; // 子節(jié)點(diǎn)事件,通過(guò)zoo_get_children() 和 zoo_get_children2()設(shè)置監(jiān)視。
- ZOO_SESSION_EVENT; // 會(huì)話丟失
- ZOO_NOTWATCHING_EVENT; // 監(jiān)視被移除。
Zookeeper C API 錯(cuò)誤碼介紹 ZOO_ERRORS
| ZOK? | 正常返回 |
| ZSYSTEMERROR? | 系統(tǒng)或服務(wù)器端錯(cuò)誤(System and server-side errors),服務(wù)器不會(huì)拋出該錯(cuò)誤,該錯(cuò)誤也只是用來(lái)標(biāo)識(shí)錯(cuò)誤范圍的,即大于該錯(cuò)誤值,且小于 ZAPIERROR 都是系統(tǒng)錯(cuò)誤。 |
| ZRUNTIMEINCONSISTENCY? | 運(yùn)行時(shí)非一致性錯(cuò)誤。 |
| ZDATAINCONSISTENCY? | 數(shù)據(jù)非一致性錯(cuò)誤。 |
| ZCONNECTIONLOSS? | Zookeeper 客戶端與服務(wù)器端失去連接 |
| ZMARSHALLINGERROR? | 在 marshalling 和unmarshalling 數(shù)據(jù)時(shí)出現(xiàn)錯(cuò)誤(Error while marshalling or unmarshalling data) |
| ZUNIMPLEMENTED? | 該操作未實(shí)現(xiàn)(Operation is unimplemented) |
| ZOPERATIONTIMEOUT? | 該操作超時(shí)(Operation timeout) |
| ZBADARGUMENTS? | 非法參數(shù)錯(cuò)誤(Invalid arguments) |
| ZINVALIDSTATE? | 非法句柄狀態(tài)(Invliad zhandle state) |
| ZAPIERROR? | API 錯(cuò)誤(API errors),服務(wù)器不會(huì)拋出該錯(cuò)誤,該錯(cuò)誤也只是用來(lái)標(biāo)識(shí)錯(cuò)誤范圍的,錯(cuò)誤值大于該值的標(biāo)識(shí) API 錯(cuò)誤,而小于該值的標(biāo)識(shí) ZSYSTEMERROR。 |
| ZNONODE? | 節(jié)點(diǎn)不存在(Node does not exist) |
| ZNOAUTH? | 沒(méi)有經(jīng)過(guò)授權(quán)(Not authenticated) |
| ZBADVERSION? | 版本沖突(Version conflict) |
| ZNOCHILDRENFOREPHEMERALS? | 臨時(shí)節(jié)點(diǎn)不能擁有子節(jié)點(diǎn)(Ephemeral nodes may not have children) |
| ZNODEEXISTS? | 節(jié)點(diǎn)已經(jīng)存在(The node already exists) |
| ZNOTEMPTY? | 該節(jié)點(diǎn)具有自身的子節(jié)點(diǎn)(The node has children) |
| ZSESSIONEXPIRED? | 會(huì)話過(guò)期(The session has been expired by the server) |
| ZINVALIDCALLBACK? | 非法的回調(diào)函數(shù)(Invalid callback specified) |
| ZINVALIDACL? | 非法的ACL(Invalid ACL specified) |
| ZAUTHFAILED? | 客戶端授權(quán)失敗(Client authentication failed) |
| ZCLOSING? | Zookeeper 連接關(guān)閉(ZooKeeper is closing) |
| ZNOTHING? | 并非錯(cuò)誤,客戶端不需要處理服務(wù)器的響應(yīng)(not error, no server responses to process) |
| ZSESSIONMOVED? | 會(huì)話轉(zhuǎn)移至其他服務(wù)器,所以操作被忽略(session moved to another server, so operation is ignored) |
?
至此,Zookeeper C API 中的大部分的常量和結(jié)構(gòu)體均已介紹完畢,下一節(jié)《Zookeeper C API 指南三(回調(diào)函數(shù))》將介紹 Zookeeper C API 中的回調(diào)函數(shù)。
接上一篇《Zookeeper C API 指南二(監(jiān)視(Wathes), 基本常量和結(jié)構(gòu)體介紹)》,本文重點(diǎn)介紹 Zookeeper C API 中的各種回調(diào)函數(shù)。
Zookeeper C API 中各種回調(diào)函數(shù)簡(jiǎn)介
在具體介紹 Zookeeper C API 之前,首先介紹一下 Zookeeper C API 中的各種回調(diào)函數(shù)的原型:
監(jiān)視函數(shù)(watch function)原型
typedef void (*watcher_fn)(zhandle_t *zh, int type, int state, const char *path,void *watcherCtx);?監(jiān)視函數(shù)原型的各個(gè)參數(shù)解釋如下:
| zh | zookeeper 句柄(handle) |
| type | 事件類型(event type). *_EVENT 常量之一. |
| state | 連接狀態(tài)(connection state). 狀態(tài)值為 *_STATE 常量之一. |
| path | 觸發(fā)監(jiān)視事件的 znode 節(jié)點(diǎn)的路徑,若為 NULL,則事件類型為 ZOO_SESSION_EVENT |
| watcherCtx | 監(jiān)視器上下文(watcher context). |
其他回調(diào)函數(shù)的原型
Zookeeper 中還有幾種在異步 API(一般以 zoo_a*開(kāi)頭的函數(shù)) 中使用的回調(diào)函數(shù),根據(jù)回調(diào)函數(shù)處理異步函數(shù)返回值類型的不同分為以下幾類:處理返回 void 類型的回調(diào)函數(shù),處理返回 Stat 結(jié)構(gòu)的回調(diào)函數(shù),處理返回字符串的回調(diào)函數(shù),處理返回?cái)?shù)據(jù)的回調(diào)函數(shù),處理返回字符串列表(a list of string)的回調(diào)函數(shù),同時(shí)處理返回字符串列表(a list of string)和 Stat 結(jié)構(gòu)的回調(diào)函數(shù),以及處理返回 ACL 信息的回調(diào)函數(shù),它們分別如下:
// 處理返回 void 類型的回調(diào)函數(shù) typedef void(* void_completion_t)(int rc, const void *data);// 處理返回 Stat 結(jié)構(gòu)的回調(diào)函數(shù) typedef void(* stat_completion_t)(int rc, const struct Stat *stat, const void *data); // 處理返回字符串的回調(diào)函數(shù) typedef void(* string_completion_t)(int rc, const char *value, const void *data); // 處理返回?cái)?shù)據(jù)的回調(diào)函數(shù) typedef void(* data_completion_t)(int rc, const char *value, int value_len, const struct Stat *stat, const void *data); // 處理返回字符串列表(a list of string)的回調(diào)函數(shù) typedef void(* strings_completion_t)(int rc, const struct String_vector *strings, const void *data); // 同時(shí)處理返回字符串列表(a list of string)和 Stat 結(jié)構(gòu)的回調(diào)函數(shù) typedef void(* strings_stat_completion_t)(int rc, const struct String_vector *strings, const struct Stat *stat, const void *data); // 處理以及返回 ACL 信息的回調(diào)函數(shù) typedef void(* acl_completion_t)(int rc, struct ACL_vector *acl, struct Stat *stat, const void *data);?下面一一介紹上述幾種回調(diào)函數(shù)的用法:
- 處理返回 void 類型的回調(diào)函數(shù)
該回調(diào)函數(shù)一般在異步 API 調(diào)用結(jié)束或 Zookeeper? 客戶端失去連接時(shí)被調(diào)用。
| rc | 異步函數(shù)調(diào)用返回的錯(cuò)誤碼,連接丟失/超時(shí)將觸發(fā)該原型函數(shù)(此處指具有該函數(shù)原型的回調(diào)函數(shù),下同)的調(diào)用,并且錯(cuò)誤碼為 ZCONNECTIONLOSS --? Zookeeper 客戶端與服務(wù)器端的連接丟失,或者 ZOPERATIONTIMEOUT -- 連接超時(shí);而與數(shù)據(jù)相關(guān)的事件也會(huì)觸發(fā)該原型函數(shù)的調(diào)用,同時(shí)置相應(yīng)的錯(cuò)誤碼,具體見(jiàn)后文(0 代異步函數(shù)調(diào)用成功) |
| data | 由調(diào)用者傳入的指針,調(diào)用者可以通過(guò)該指針向回調(diào)函數(shù)傳入自定義的參數(shù),開(kāi)發(fā)人員應(yīng)負(fù)責(zé)此指針?biāo)赶騼?nèi)存的釋放。 |
?
- 處理返回 Stat 結(jié)構(gòu)的回調(diào)函數(shù)
該函數(shù)一般在異步 API 調(diào)用結(jié)束或 Zookeeper? 客戶端失去連接時(shí)被調(diào)用。
| rc | 異步函數(shù)調(diào)用返回的錯(cuò)誤碼,連接丟失/超時(shí)將觸發(fā)該原型函數(shù)(此處指具有該函數(shù)原型的回調(diào)函數(shù),下同)的調(diào)用,并且錯(cuò)誤碼為 ZCONNECTIONLOSS --? Zookeeper 客戶端與服務(wù)器端的連接丟失,或者 ZOPERATIONTIMEOUT -- 連接超時(shí);而與數(shù)據(jù)相關(guān)的事件也會(huì)觸發(fā)該原型函數(shù)的調(diào)用,同時(shí)置相應(yīng)的錯(cuò)誤碼,具體見(jiàn)后文(0 代異步函數(shù)調(diào)用成功) |
| stat | 指向與該 znode 節(jié)點(diǎn)相關(guān)的 Stat 信息,如果返回非 0 值(即異步調(diào)用函數(shù)出錯(cuò)),stat 所指向的區(qū)域是未定義的,開(kāi)發(fā)者不負(fù)責(zé)釋放 stat 所指向的內(nèi)存空間。 |
| data | 由調(diào)用者傳入的指針,調(diào)用者可以通過(guò)該指針向回調(diào)函數(shù)傳入自定義的參數(shù),開(kāi)發(fā)人員應(yīng)負(fù)責(zé)此指針?biāo)赶騼?nèi)存的釋放。 |
?
- 處理返回字符串的回調(diào)函數(shù)
該函數(shù)一般在異步 API 調(diào)用結(jié)束或 Zookeeper? 客戶端失去連接時(shí)被調(diào)用。
| rc | 異步函數(shù)調(diào)用返回的錯(cuò)誤碼,連接丟失/超時(shí)將觸發(fā)該原型函數(shù)(此處指具有該函數(shù)原型的回調(diào)函數(shù),下同)的調(diào)用,并且錯(cuò)誤碼為 ZCONNECTIONLOSS --? Zookeeper 客戶端與服務(wù)器端的連接丟失,或者 ZOPERATIONTIMEOUT -- 連接超時(shí);而與數(shù)據(jù)相關(guān)的事件也會(huì)觸發(fā)該原型函數(shù)的調(diào)用,同時(shí)置相應(yīng)的錯(cuò)誤碼,具體見(jiàn)后文(0 代異步函數(shù)調(diào)用成功) |
| value | 返回的字符串 |
| data | 由調(diào)用者傳入的指針,調(diào)用者可以通過(guò)該指針向回調(diào)函數(shù)傳入自定義的參數(shù),開(kāi)發(fā)人員應(yīng)負(fù)責(zé)此指針?biāo)赶騼?nèi)存的釋放。 |
?
- 處理返回?cái)?shù)據(jù)的回調(diào)函數(shù)
該函數(shù)一般在異步 API 調(diào)用結(jié)束或 Zookeeper? 客戶端失去連接時(shí)被調(diào)用。
| rc | 異步函數(shù)調(diào)用返回的錯(cuò)誤碼,連接丟失/超時(shí)將觸發(fā)該原型函數(shù)(此處指具有該函數(shù)原型的回調(diào)函數(shù),下同)的調(diào)用,并且錯(cuò)誤碼為 ZCONNECTIONLOSS --? Zookeeper 客戶端與服務(wù)器端的連接丟失,或者 ZOPERATIONTIMEOUT -- 連接超時(shí);而與數(shù)據(jù)相關(guān)的事件也會(huì)觸發(fā)該原型函數(shù)的調(diào)用,同時(shí)置相應(yīng)的錯(cuò)誤碼,具體見(jiàn)后文(0 代異步函數(shù)調(diào)用成功) |
| value | 異步調(diào)用的返回值,如果返回非 0 值(即異步調(diào)用函數(shù)出錯(cuò)),value 所指向的區(qū)域是未定義的,開(kāi)發(fā)者不負(fù)責(zé)釋放?value 所指向的內(nèi)存空間。 |
| value_len | 返回 value 數(shù)據(jù)字節(jié)數(shù)(bytes) |
| stat | 指向與該 znode 節(jié)點(diǎn)相關(guān)的 Stat 信息,如果返回非 0 值(即異步調(diào)用函數(shù)出錯(cuò)),stat 所指向的區(qū)域是未定義的,開(kāi)發(fā)者不負(fù)責(zé)釋放 stat 所指向的內(nèi)存空間。 |
| data | 由調(diào)用者傳入的指針,調(diào)用者可以通過(guò)該指針向回調(diào)函數(shù)傳入自定義的參數(shù),開(kāi)發(fā)人員應(yīng)負(fù)責(zé)此指針?biāo)赶騼?nèi)存的釋放。 |
?
- 處理返回字符串列表(a list of string)的回調(diào)函數(shù)
該函數(shù)一般在異步 API 調(diào)用結(jié)束或 Zookeeper? 客戶端失去連接時(shí)被調(diào)用。
| rc | 異步函數(shù)調(diào)用返回的錯(cuò)誤碼,連接丟失/超時(shí)將觸發(fā)該原型函數(shù)(此處指具有該函數(shù)原型的回調(diào)函數(shù),下同)的調(diào)用,并且錯(cuò)誤碼為 ZCONNECTIONLOSS --? Zookeeper 客戶端與服務(wù)器端的連接丟失,或者 ZOPERATIONTIMEOUT -- 連接超時(shí);而與數(shù)據(jù)相關(guān)的事件也會(huì)觸發(fā)該原型函數(shù)的調(diào)用,同時(shí)置相應(yīng)的錯(cuò)誤碼,具體見(jiàn)后文(0 代異步函數(shù)調(diào)用成功) |
| strings | 指向包含了某 znode 節(jié)點(diǎn)的所有子節(jié)點(diǎn)名稱列表的結(jié)構(gòu),如果返回非 0 值(即異步調(diào)用函數(shù)出錯(cuò)),strings 所指向的區(qū)域是未定義的,開(kāi)發(fā)者不負(fù)責(zé)釋放strings 所指向的內(nèi)存空間。 |
| data | 由調(diào)用者傳入的指針,調(diào)用者可以通過(guò)該指針向回調(diào)函數(shù)傳入自定義的參數(shù),開(kāi)發(fā)人員應(yīng)負(fù)責(zé)此指針?biāo)赶騼?nèi)存的釋放。 |
?
- 同時(shí)處理返回字符串列表(a list of string)和 Stat 結(jié)構(gòu)的回調(diào)函數(shù)
該函數(shù)一般在異步 API 調(diào)用結(jié)束或 Zookeeper? 客戶端失去連接時(shí)被調(diào)用。
| rc | 異步函數(shù)調(diào)用返回的錯(cuò)誤碼,連接丟失/超時(shí)將觸發(fā)該原型函數(shù)(此處指具有該函數(shù)原型的回調(diào)函數(shù),下同)的調(diào)用,并且錯(cuò)誤碼為 ZCONNECTIONLOSS --? Zookeeper 客戶端與服務(wù)器端的連接丟失,或者 ZOPERATIONTIMEOUT -- 連接超時(shí);而與數(shù)據(jù)相關(guān)的事件也會(huì)觸發(fā)該原型函數(shù)的調(diào)用,同時(shí)置相應(yīng)的錯(cuò)誤碼,具體見(jiàn)后文(0 代異步函數(shù)調(diào)用成功) |
| strings | 指向包含了某 znode 節(jié)點(diǎn)的所有子節(jié)點(diǎn)名稱列表的結(jié)構(gòu),如果返回非 0 值(即異步調(diào)用函數(shù)出錯(cuò)),strings 所指向的區(qū)域是未定義的,開(kāi)發(fā)者不負(fù)責(zé)釋放strings 所指向的內(nèi)存空間。 |
| stat | 指向與該 znode 節(jié)點(diǎn)相關(guān)的 Stat 信息,如果返回非 0 值(即異步調(diào)用函數(shù)出錯(cuò)),stat 所指向的區(qū)域是未定義的,開(kāi)發(fā)者不負(fù)責(zé)釋放 stat 所指向的內(nèi)存空間。 |
| data | 由調(diào)用者傳入的指針,調(diào)用者可以通過(guò)該指針向回調(diào)函數(shù)傳入自定義的參數(shù),開(kāi)發(fā)人員應(yīng)負(fù)責(zé)此指針?biāo)赶騼?nèi)存的釋放。 |
?
- 處理返回 ACL 信息的回調(diào)函數(shù)
該函數(shù)一般在異步 API 調(diào)用結(jié)束或 Zookeeper? 客戶端失去連接時(shí)被調(diào)用。
| rc | 異步函數(shù)調(diào)用返回的錯(cuò)誤碼,連接丟失/超時(shí)將觸發(fā)該原型函數(shù)(此處指具有該函數(shù)原型的回調(diào)函數(shù),下同)的調(diào)用,并且錯(cuò)誤碼為 ZCONNECTIONLOSS --? Zookeeper 客戶端與服務(wù)器端的連接丟失,或者 ZOPERATIONTIMEOUT -- 連接超時(shí);而與數(shù)據(jù)相關(guān)的事件也會(huì)觸發(fā)該原型函數(shù)的調(diào)用,同時(shí)置相應(yīng)的錯(cuò)誤碼,具體見(jiàn)后文(0 代異步函數(shù)調(diào)用成功) |
| acl | 指向包含某 znode 節(jié)點(diǎn) ACL 信息的指針,如果返回非 0 值(即異步調(diào)用函數(shù)出錯(cuò)),acl 所指向的區(qū)域是未定義的,開(kāi)發(fā)者不負(fù)責(zé)釋放 acl 所指向的內(nèi)存空間。 |
| stat | 指向與該 znode 節(jié)點(diǎn)相關(guān)的 Stat 信息,如果返回非 0 值(即異步調(diào)用函數(shù)出錯(cuò)),stat 所指向的區(qū)域是未定義的,開(kāi)發(fā)者不負(fù)責(zé)釋放 stat 所指向的內(nèi)存空間。 |
| data | 由調(diào)用者傳入的指針,調(diào)用者可以通過(guò)該指針向回調(diào)函數(shù)傳入自定義的參數(shù),開(kāi)發(fā)人員應(yīng)負(fù)責(zé)此指針?biāo)赶騼?nèi)存的釋放。 |
?
至此,所有的回調(diào)函數(shù)均已介紹完畢,下一節(jié)將介紹 Zookeeper C API 分類和基本 API 的使用,見(jiàn)第四講《Zookeeper C API 指南四(C API 概覽)》
上一節(jié)《Zookeeper C API 指南三(回調(diào)函數(shù))》重點(diǎn)講了 Zookeeper C API 中各種回調(diào)函數(shù)的原型,本節(jié)將切入正題,正式講解 Zookeeper C API。相信大家讀完本文后應(yīng)該對(duì) Zookeeper C API 的使用有一個(gè)比較清晰的認(rèn)識(shí)。
Zookeeper C API 概覽
Zookeeper C API 很規(guī)范,接口很容易記憶,大部分接口均以 zoo_ 開(kāi)頭,只有少量接口以 zookeeper_ 開(kāi)頭,所有的 API 匯總?cè)缦?#xff1a;
void zoo_create_op_init(zoo_op_t * op, const char *path, const char *value,int valuelen, const struct ACL_vector *acl,int flags, char *path_buffer, int path_buffer_len);void zoo_delete_op_init(zoo_op_t * op, const char *path, int version);void zoo_set_op_init(zoo_op_t * op, const char *path,const char *buffer, int buflen, int version,struct Stat *stat);void zoo_check_op_init(zoo_op_t * op, const char *path, int version);ZOOAPI zhandle_t *zookeeper_init(const char *host, watcher_fn fn,int recv_timeout,const clientid_t * clientid,void *context, int flags);ZOOAPI int zookeeper_close(zhandle_t * zh);ZOOAPI const clientid_t *zoo_client_id(zhandle_t * zh);ZOOAPI int zoo_recv_timeout(zhandle_t * zh);ZOOAPI const void *zoo_get_context(zhandle_t * zh);ZOOAPI void zoo_set_context(zhandle_t * zh, void *context);ZOOAPI watcher_fn zoo_set_watcher(zhandle_t * zh, watcher_fn newFn);ZOOAPI struct sockaddr *zookeeper_get_connected_host(zhandle_t * zh, struct sockaddr*addr,socklen_t * addr_len);ZOOAPI int zookeeper_interest(zhandle_t * zh, int *fd, int *interest,struct timeval *tv);ZOOAPI int zookeeper_process(zhandle_t * zh, int events);ZOOAPI int zoo_state(zhandle_t * zh);ZOOAPI 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);ZOOAPI int zoo_adelete(zhandle_t * zh, const char *path, int version,void_completion_t completion, const void *data);ZOOAPI int zoo_aexists(zhandle_t * zh, const char *path, int watch,stat_completion_t completion, const void *data);ZOOAPI int zoo_awexists(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,stat_completion_t completion, const void *data);ZOOAPI int zoo_aget(zhandle_t * zh, const char *path, int watch,data_completion_t completion, const void *data);ZOOAPI int zoo_awget(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,data_completion_t completion, const void *data);ZOOAPI int zoo_aset(zhandle_t * zh, const char *path,const char *buffer, int buflen, int version,stat_completion_t completion, const void *data);ZOOAPI int zoo_aget_children(zhandle_t * zh, const char *path,int watch,strings_completion_t completion,const void *data);ZOOAPI int zoo_awget_children(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,strings_completion_t completion,const void *data);ZOOAPI int zoo_aget_children2(zhandle_t * zh, const char *path,int watch,strings_stat_completion_t completion,const void *data);ZOOAPI int zoo_awget_children2(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,strings_stat_completion_t completion,const void *data);ZOOAPI int zoo_async(zhandle_t * zh, const char *path,string_completion_t completion, const void *data);ZOOAPI int zoo_aget_acl(zhandle_t * zh, const char *path,acl_completion_t completion, const void *data);ZOOAPI int zoo_aset_acl(zhandle_t * zh, const char *path, int version,struct ACL_vector *acl, void_completion_t,const void *data);ZOOAPI int zoo_amulti(zhandle_t * zh, int count, const zoo_op_t * ops,zoo_op_result_t * results, void_completion_t,const void *data);ZOOAPI const char *zerror(int c);ZOOAPI int zoo_add_auth(zhandle_t * zh, const char *scheme,const char *cert, int certLen,void_completion_t completion, const void *data);ZOOAPI int is_unrecoverable(zhandle_t * zh);ZOOAPI void zoo_set_debug_level(ZooLogLevel logLevel);ZOOAPI void zoo_set_log_stream(FILE * logStream);ZOOAPI void zoo_deterministic_conn_order(int yesOrNo);ZOOAPI int zoo_create(zhandle_t * zh, const char *path,const char *value, int valuelen,const struct ACL_vector *acl, int flags,char *path_buffer, int path_buffer_len);ZOOAPI int zoo_delete(zhandle_t * zh, const char *path, int version);ZOOAPI int zoo_exists(zhandle_t * zh, const char *path, int watch,struct Stat *stat);ZOOAPI int zoo_wexists(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct Stat *stat);ZOOAPI int zoo_get(zhandle_t * zh, const char *path, int watch,char *buffer, int *buffer_len, struct Stat *stat);ZOOAPI int zoo_wget(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,char *buffer, int *buffer_len, struct Stat *stat);ZOOAPI int zoo_set(zhandle_t * zh, const char *path,const char *buffer, int buflen, int version);ZOOAPI int zoo_set2(zhandle_t * zh, const char *path,const char *buffer, int buflen, int version,struct Stat *stat);ZOOAPI int zoo_get_children(zhandle_t * zh, const char *path,int watch, struct String_vector *strings);ZOOAPI int zoo_wget_children(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct String_vector *strings);ZOOAPI int zoo_get_children2(zhandle_t * zh, const char *path,int watch, struct String_vector *strings,struct Stat *stat);ZOOAPI int zoo_wget_children2(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct String_vector *strings,struct Stat *stat);ZOOAPI int zoo_get_acl(zhandle_t * zh, const char *path,struct ACL_vector *acl, struct Stat *stat);ZOOAPI int zoo_set_acl(zhandle_t * zh, const char *path, int version,const struct ACL_vector *acl);ZOOAPI int zoo_multi(zhandle_t * zh, int count, const zoo_op_t * ops,zoo_op_result_t * results);除了基本的初始化、銷毀 Zookeeper 句柄(zhandle),設(shè)置日志等級(jí)、日志流以及一些具有輔助功能 API(zerror(), zoo_state()等) 外,Zookeeper C API 大部分接口可以根據(jù)同步和異步特性分為兩類,同步接口以 zoo_* 開(kāi)頭,異步接口以則以 zoo_a* 開(kāi)頭。并且除了 zookeeper_init() 以及與 zoo_multi() 或 zoo_amulti() 批量操作相關(guān)的 zoo_op_t 初始化外,其他的 API 的第一個(gè)參數(shù)均為 zhandle_t * zh, 即 Zookeeper 句柄的指針。
Zookeeper C API 分類
- 初始化、銷毀 Zookeeper 句柄
- 輔助函數(shù)
- 與 zoo_multi() 和 zoo_amulti() 批量操作相關(guān)的 zoo_op_t 初始化
- Zookeeper C API 同步接口
- Zookeeper C API 異步接口
?Zookeeper C API 初體驗(yàn)
有了上面的介紹,下面我們來(lái)看一看如何使簡(jiǎn)單地使用 Zookeeper C API 吧。
在使用 Zookeeper C API 時(shí)應(yīng)注意:
- 頭文件包含 #include <zookeeper/zookeeper.h>
- 如果你需要編譯多線程版本客戶端程序,請(qǐng)?zhí)砑泳幾g選項(xiàng) -DTHREADED,同時(shí)鏈接時(shí)應(yīng)鏈接?zookeeper_mt 庫(kù);如果你需要編譯單線程客戶端程序,請(qǐng)不要添加編譯選項(xiàng) -DTHREADED,同時(shí)鏈接時(shí)應(yīng)鏈接?zookeeper_st 庫(kù)。
一個(gè)基本的程序如下(更詳細(xì)的例子可以參看 src/c/src/cli.c):
/** =============================================================================** Filename: zktest.c** Description: zookeeper api testcase.** Created: 02/15/2013 08:48:49 PM** Author: Fu Haiping (forhappy), haipingf@gmail.com* Company: ICT ( Institute Of Computing Technology, CAS )** =============================================================================*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <zookeeper/zookeeper.h> #include <zookeeper/zookeeper_log.h>void zktest_watcher_g(zhandle_t* zh, int type, int state,const char* path, void* watcherCtx) {printf("Something happened.\n");printf("type: %d\n", type);printf("state: %d\n", state);printf("path: %s\n", path);printf("watcherCtx: %s\n", (char *)watcherCtx); }void zktest_dump_stat(const struct Stat *stat) {char tctimes[40];char tmtimes[40];time_t tctime;time_t tmtime;if (!stat) {fprintf(stderr,"null\n");return;}tctime = stat->ctime/1000;tmtime = stat->mtime/1000;ctime_r(&tmtime, tmtimes);ctime_r(&tctime, tctimes);fprintf(stderr, "\tctime = %s\tczxid=%llx\n""\tmtime=%s\tmzxid=%llx\n""\tversion=%x\taversion=%x\n""\tephemeralOwner = %llx\n",tctimes, stat->czxid,tmtimes, stat->mzxid,(unsigned int)stat->version, (unsigned int)stat->aversion,stat->ephemeralOwner); }void zktest_stat_completion(int rc, const struct Stat *stat, const void *data) {fprintf(stderr, "%s: rc = %d Stat:\n", (char*)data, rc);zktest_dump_stat(stat); }void zktest_void_completion(int rc, const void *data) {fprintf(stderr, "[%s]: rc = %d\n", (char*)(data==0?"null":data), rc); }void zktest_string_completion(int rc, const char *name, const void *data) {fprintf(stderr, "[%s]: rc = %d\n", (char*)(data==0?"null":data), rc);if (!rc) {fprintf(stderr, "\tname = %s\n", name);} }int main(int argc, const char *argv[]) {const char* host = "127.0.0.1:2181,127.0.0.1:2182,""127.0.0.1:2183,127.0.0.1:2184,127.0.0.1:2185";int timeout = 30000;zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);zhandle_t* zkhandle = zookeeper_init(host,zktest_watcher_g, timeout, 0, "hello zookeeper.", 0);if (zkhandle == NULL) {fprintf(stderr, "Error when connecting to zookeeper servers...\n");exit(EXIT_FAILURE);}// struct ACL ALL_ACL[] = {{ZOO_PERM_ALL, ZOO_ANYONE_ID_UNSAFE}};// struct ACL_vector ALL_PERMS = {1, ALL_ACL};int ret = zoo_acreate(zkhandle, "/xyz", "hello", 5,&ZOO_OPEN_ACL_UNSAFE, 0 /* ZOO_SEQUENCE */,zktest_string_completion, "acreate");if (ret) {fprintf(stderr, "Error %d for %s\n", ret, "acreate");exit(EXIT_FAILURE);}ret = 0;ret = zoo_aexists(zkhandle, "/xyz", 1, zktest_stat_completion, "aexists");if (ret) {fprintf(stderr, "Error %d for %s\n", ret, "aexists");exit(EXIT_FAILURE);}ret = 0;// Wait for asynchronous zookeeper call done. getchar();ret = zoo_adelete(zkhandle, "/xyz", -1, zktest_void_completion, "adelete");if (ret) {fprintf(stderr, "Error %d for %s\n", ret, "adelete");exit(EXIT_FAILURE);}// Wait for asynchronous zookeeper call done. getchar();zookeeper_close(zkhandle); }下面簡(jiǎn)單講講這個(gè)程序的結(jié)構(gòu):
- 首先聲明 host, timeout 變量。
其中 host 字符串格式為逗號(hào)隔開(kāi)的 IP:PORT對(duì),可以是 Zookeeper 集群中的全部或部分 Zookeeper 實(shí)例的 IP:PORT對(duì),我們?cè)诘谝恢v《準(zhǔn)備工作》中介紹了如何部署一個(gè)偽分布式的集群,上述的 host 就是這些 zookeeper 實(shí)例的IP:PORT對(duì)。
另外 timeout 是 Zookeeper 客戶端連接服務(wù)器的超時(shí)時(shí)間,單位為毫秒,timeout = 30000 說(shuō)明如果 30 秒內(nèi)客戶端沒(méi)有連接上 Zookeeper 服務(wù)則表示連接超時(shí)。
- 設(shè)置日志等級(jí)。
- 初始化 Zookeeper 句柄(zhandle_t)。
初始化 Zookeeper 句柄 zookeeper_init() 函數(shù)原型如下:
ZOOAPI zhandle_t *zookeeper_init(const char *host, watcher_fn fn,int recv_timeout,const clientid_t * clientid,void *context, int flags);各個(gè)參數(shù)解釋如下:
| host | 逗號(hào)隔開(kāi)的 host:port 對(duì), 每個(gè)代表一個(gè) zk server, 例如: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" |
| fn | 全局的監(jiān)視器回調(diào)函數(shù),當(dāng)發(fā)生事件通知時(shí),該函數(shù)會(huì)被調(diào)用。 |
| clientid | 客戶端嘗試重連的先前會(huì)話的ID,如果不需要重連先前的會(huì)話,則設(shè)置為 0。客戶端可以通過(guò)調(diào)用 zoo_client_id來(lái)訪問(wèn)一個(gè)已經(jīng)連接上的并且有效的會(huì)話ID,如果clientid對(duì)應(yīng)的會(huì)話超時(shí),或者由于某種原因 clientid變?yōu)闊o(wú)效了,那么zookeeper_init 將返回一個(gè)非法的zhandle_t, 通過(guò) zhandle_t 的狀態(tài)可以獲知zookeeper_init 調(diào)用失敗的原因。 (通常為 ZOO_EXPIRED_SESSION_STATE). |
| context | 與 zhandle_t 實(shí)例相關(guān)聯(lián)的“上下文對(duì)象”(可以通過(guò)該參數(shù)為 zhandle_t 傳入自定義類型的數(shù)據(jù)),應(yīng)用程序可以通過(guò) zoo_get_context訪問(wèn)它(例如在監(jiān)視器回調(diào)函數(shù)中),當(dāng)然 zookeeper 內(nèi)部沒(méi)有用到該參數(shù),所以 context 可以設(shè)置為 NULL。 |
| flags | 目前為保留參數(shù),設(shè)置為 0。 |
- 創(chuàng)建一個(gè) znode 節(jié)點(diǎn)。
這里采用異步方式創(chuàng)建 znode 節(jié)點(diǎn),zoo_acreate() 函數(shù)原型為:
ZOOAPI 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);各個(gè)參數(shù)解釋如下:
| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| value | 該節(jié)點(diǎn)保存的數(shù)據(jù)。 |
| valuelen | 該節(jié)點(diǎn)保存數(shù)據(jù)的大小。 |
| acl | 該節(jié)點(diǎn)初始 ACL,ACL 不能為null 或空。 |
| flags | 該參數(shù)可以設(shè)置為 0,或者創(chuàng)建標(biāo)識(shí)符 ZOO_EPHEMERAL,?ZOO_SEQUENCE 的組合或(OR)。 |
| completion | 當(dāng)創(chuàng)建節(jié)點(diǎn)請(qǐng)求完成時(shí)會(huì)調(diào)用該函數(shù),該函數(shù)原型詳見(jiàn)第三講《回調(diào)函數(shù)》一節(jié)。同時(shí)傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 父節(jié)點(diǎn)不存在;ZNODEEXISTS 節(jié)點(diǎn)已存在;ZNOAUTH 客戶端沒(méi)有權(quán)限創(chuàng)建節(jié)點(diǎn)。ZNOCHILDRENFOREPHEMERALS 臨時(shí)節(jié)點(diǎn)不能創(chuàng)建子節(jié)點(diǎn)。 |
| data | completino函數(shù)被調(diào)用時(shí),傳遞給 completion 的數(shù)據(jù)。 |
- 調(diào)用 exists() 函數(shù),設(shè)置監(jiān)視器。
- 調(diào)用 delete 函數(shù),刪除 znode 節(jié)點(diǎn)。
- 銷毀 zookeeper 句柄
好了,至此本文大致講完了 Zookeeper C API 的分類和幾個(gè)基本函數(shù)的用法。之所以為 Zookeeper C API 分類是方便記憶,開(kāi)發(fā)者可以迅速找到自己需要的 API;另外,本文還講了幾個(gè)基本函數(shù)的使用方法,包括 zookeeper_init(),zoo_acreate(), zoo_aexists(), zoo_adelete() 以及 zookeeper_close()。相信大家對(duì) Zookeeper C API 也有了一個(gè)大致的了解,第五講我會(huì)給大家介紹 Zookeeper C API 中的同步調(diào)用的函數(shù)(即以 zoo_* 開(kāi)頭的函數(shù)),然后第六講給大家介紹 Zookeeper C API 中的異步調(diào)用的函數(shù)(即以 zoo_a* 開(kāi)頭的函數(shù))。
上一講《Zookeeper C API 指南四(C API 概覽)》講了Zookeeper C API 的分類和幾個(gè)基本函數(shù)的用法,相信大家對(duì) Zookeeper C API 也有了一個(gè)大致的了解,本文我會(huì)給大家介紹 Zookeeper C API 中的同步調(diào)用的函數(shù)(即以 zoo_* 開(kāi)頭的函數(shù))。
Zookeeper C API 中與訪問(wèn) Zookeeper 服務(wù)相關(guān)(比如創(chuàng)建、刪除 znode 節(jié)點(diǎn),獲取子節(jié)點(diǎn),設(shè)置 znode 數(shù)據(jù)等)的同步 API 如下:
ZOOAPI int zoo_add_auth(zhandle_t * zh, const char *scheme,const char *cert, int certLen,void_completion_t completion, const void *data);ZOOAPI int zoo_create(zhandle_t * zh, const char *path,const char *value, int valuelen,const struct ACL_vector *acl, int flags,char *path_buffer, int path_buffer_len);ZOOAPI int zoo_delete(zhandle_t * zh, const char *path, int version);ZOOAPI int zoo_exists(zhandle_t * zh, const char *path, int watch,struct Stat *stat);ZOOAPI int zoo_wexists(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct Stat *stat);ZOOAPI int zoo_get(zhandle_t * zh, const char *path, int watch,char *buffer, int *buffer_len, struct Stat *stat);ZOOAPI int zoo_wget(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,char *buffer, int *buffer_len, struct Stat *stat);ZOOAPI int zoo_set(zhandle_t * zh, const char *path,const char *buffer, int buflen, int version);ZOOAPI int zoo_set2(zhandle_t * zh, const char *path,const char *buffer, int buflen, int version,struct Stat *stat);ZOOAPI int zoo_get_children(zhandle_t * zh, const char *path,int watch, struct String_vector *strings);ZOOAPI int zoo_wget_children(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct String_vector *strings);ZOOAPI int zoo_get_children2(zhandle_t * zh, const char *path,int watch, struct String_vector *strings,struct Stat *stat);ZOOAPI int zoo_wget_children2(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct String_vector *strings,struct Stat *stat);ZOOAPI int zoo_get_acl(zhandle_t * zh, const char *path,struct ACL_vector *acl, struct Stat *stat);ZOOAPI int zoo_set_acl(zhandle_t * zh, const char *path, int version,const struct ACL_vector *acl);ZOOAPI int zoo_multi(zhandle_t * zh, int count, const zoo_op_t * ops,zoo_op_result_t * results);本文將以上同步 API 在此細(xì)分為一下幾類:(1). 創(chuàng)建、刪除 znode 節(jié)點(diǎn),(2). 可設(shè)置 watch 的 API,(3). 訪問(wèn)、設(shè)置節(jié)點(diǎn) ACL 的 API,(4). 批處理 API
- 創(chuàng)建、刪除 znode 節(jié)點(diǎn)(兩個(gè))
- 創(chuàng)建 znode 節(jié)點(diǎn):
| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| value | 該節(jié)點(diǎn)保存的數(shù)據(jù)。 |
| valuelen | 該節(jié)點(diǎn)保存數(shù)據(jù)的大小。如果 value 被設(shè)置為 NULL(該 znode 節(jié)點(diǎn)不包含數(shù)據(jù)),則 valuelen 應(yīng)該設(shè)置為 -1。 |
| acl | 該節(jié)點(diǎn)初始 ACL,ACL 不能為null 或空。 |
| flags | 該參數(shù)可以設(shè)置為 0,或者創(chuàng)建標(biāo)識(shí)符ZOO_EPHEMERAL,?ZOO_SEQUENCE 的組合或(OR)。 |
| path_buffer | 用于保存返回節(jié)點(diǎn)新路徑(因?yàn)樵O(shè)置了ZOO_SEQUENCE 后 zoo_create 所創(chuàng)建的節(jié)點(diǎn)名稱與參數(shù) path 提供的名稱不同,新的節(jié)點(diǎn)名稱后面填充了序號(hào)),path 字符串以 NULL 結(jié)束。path_buffer 可以設(shè)置為 NULL,此時(shí) path_buffer_len 等于 0。 |
| path_buffer_len | path_buffer 的長(zhǎng)度,如果新節(jié)點(diǎn)名稱的長(zhǎng)度大于path_buffer_len,則節(jié)點(diǎn)名稱將會(huì)被截?cái)?#xff0c;而服務(wù)器端該節(jié)點(diǎn)的名稱不會(huì)截?cái)唷?/span> |
- 刪除 znode 節(jié)點(diǎn):
| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| version | 節(jié)點(diǎn)的版本號(hào),如果該 znode 節(jié)點(diǎn)的實(shí)際版本號(hào)與該參數(shù)提供的版本號(hào)不一值,則刪除節(jié)點(diǎn)失敗,如果 version 為 -1,則不作版本檢查。 |
?
- 可設(shè)置 watch 的 API(exists(兩個(gè)) + get(兩個(gè)) + get_children(四個(gè)) = 八個(gè))
- 檢查節(jié)點(diǎn)狀態(tài) exists(兩個(gè),分別是 zoo_exists() 和 zoo_wexists(),區(qū)別是后者可以指定單獨(dú)的 watcher_fn(監(jiān)視器回調(diào)函數(shù)),而前者只能用 zookeeper_init() 設(shè)置的全局監(jiān)視器回調(diào)函數(shù),同時(shí) get 和 get_children兩族函數(shù)也一樣,帶有zoo_w* 的函數(shù)可以指定單獨(dú)的 watcher_fn)。
| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| watch | 如果非 0,則在服務(wù)器端設(shè)置監(jiān)視,當(dāng)節(jié)點(diǎn)發(fā)生變化時(shí)客戶端會(huì)得到通知,即使當(dāng)前指定的節(jié)點(diǎn)不存在也會(huì)設(shè)置監(jiān)視,這樣該節(jié)點(diǎn)被創(chuàng)建時(shí),客戶端也可以得到通知。 |
| stat | 返回的 Stat 信息。 |
?
ZOOAPI int zoo_wexists(zhandle_t * zh, const char *path, watcher_fn watcher, void *watcherCtx,struct Stat *stat);| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| watcher | 如果不為 NULL 則會(huì)在服務(wù)器端設(shè)置監(jiān)視,當(dāng)節(jié)點(diǎn)發(fā)生變化時(shí)客戶端會(huì)得到通知,即使當(dāng)前指定的節(jié)點(diǎn)不存在也會(huì)設(shè)置監(jiān)視,這樣該節(jié)點(diǎn)被創(chuàng)建時(shí),客戶端也可以得到通知。 |
| watcherCtx | 用戶指定的數(shù)據(jù),將被傳入到監(jiān)視器回調(diào)函數(shù)中,與由 zookeeper_init() 設(shè)置的全局監(jiān)視器上下文不同,該函數(shù)設(shè)置的監(jiān)視器上下文只與當(dāng)前的監(jiān)視器相關(guān)聯(lián)。 |
| stat | 返回的 Stat 信息。 |
?
- 獲取節(jié)點(diǎn)數(shù)據(jù) get(兩個(gè))
| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| watch | 如果非0,則在服務(wù)器端設(shè)置監(jiān)視,當(dāng)節(jié)點(diǎn)發(fā)生變化時(shí)客戶端會(huì)得到通知。 |
| buffer | 用于保存從 zookeeper 服務(wù)器獲取的節(jié)點(diǎn)數(shù)據(jù)。 |
| buffer_len | buffer 大小,一旦成功返回該值將會(huì)被設(shè)置為節(jié)點(diǎn)數(shù)據(jù)的實(shí)際大小,如果節(jié)點(diǎn)的數(shù)據(jù)為空,則數(shù)據(jù)大小為 -1,buffer_len 也為 -1。 |
| stat | 如果非空,stat 指向的結(jié)構(gòu)將會(huì)保存該節(jié)點(diǎn)的 Stat 信息。 |
?
ZOOAPI int zoo_wget(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,char *buffer, int *buffer_len, struct Stat *stat);| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| watcher | 如果不為 NULL 則會(huì)在服務(wù)器端設(shè)置監(jiān)視,當(dāng)節(jié)點(diǎn)發(fā)生變化時(shí)客戶端會(huì)得到通知。 |
| watcherCtx | 用戶指定的數(shù)據(jù),將被傳入到監(jiān)視器回調(diào)函數(shù)中,與由 zookeeper_init() 設(shè)置的全局監(jiān)視器上下文不同,該函數(shù)設(shè)置的監(jiān)視器上下文只與當(dāng)前的監(jiān)視器相關(guān)聯(lián)。 |
| buffer | 用于保存從 zookeeper 服務(wù)器獲取的節(jié)點(diǎn)數(shù)據(jù)。 |
| buffer_len | buffer 大小,一旦成功返回該值將會(huì)被設(shè)置為節(jié)點(diǎn)數(shù)據(jù)的實(shí)際大小,如果節(jié)點(diǎn)的數(shù)據(jù)為空,則數(shù)據(jù)大小為 -1,buffer_len 也為 -1。 |
| stat | 如果非空,stat 指向的結(jié)構(gòu)將會(huì)保存該節(jié)點(diǎn)的 Stat 信息。 |
- 獲取子節(jié)點(diǎn)列表 get_children(四個(gè))
| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| watch | 如果非0,則在服務(wù)器端設(shè)置監(jiān)視,當(dāng)節(jié)點(diǎn)發(fā)生變化時(shí)客戶端會(huì)得到通知。 |
| strings | 返回各個(gè)子節(jié)點(diǎn)路徑 |
?
ZOOAPI int zoo_wget_children(zhandle_t * zh, const char *path, watcher_fn watcher, void *watcherCtx,struct String_vector *strings);| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| watcher | 如果不為 NULL 則會(huì)在服務(wù)器端設(shè)置監(jiān)視,當(dāng)節(jié)點(diǎn)發(fā)生變化時(shí)客戶端會(huì)得到通知。 |
| watcherCtx | 用戶指定的數(shù)據(jù),將被傳入到監(jiān)視器回調(diào)函數(shù)中,與由 zookeeper_init() 設(shè)置的全局監(jiān)視器上下文不同,該函數(shù)設(shè)置的監(jiān)視器上下文只與當(dāng)前的監(jiān)視器相關(guān)聯(lián)。 |
| strings | 回各個(gè)子節(jié)點(diǎn)路徑 |
?
ZOOAPI int zoo_get_children2(zhandle_t * zh, const char *path, int watch, struct String_vector *strings,struct Stat *stat);該函數(shù)最早出現(xiàn)在 Zookeeper 3.3.0中,該函數(shù)功能與 zoo_get_children() 基本一致,但同時(shí)還會(huì)返回指定節(jié)點(diǎn)的 Stat 信息。
| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| watch | 如果非0,則在服務(wù)器端設(shè)置監(jiān)視,當(dāng)節(jié)點(diǎn)發(fā)生變化時(shí)客戶端會(huì)得到通知。 |
| strings | 返回各個(gè)子節(jié)點(diǎn)路徑。 |
| stat | 返回指定節(jié)點(diǎn)的 Stat 信息。 |
?
ZOOAPI int zoo_wget_children2(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct String_vector *strings,struct Stat *stat);該函數(shù)最早出現(xiàn)在 Zookeeper 3.3.0中,該函數(shù)功能與 zoo_wget_children() 基本一致,但同時(shí)還會(huì)返回指定節(jié)點(diǎn)的 Stat 信息。
| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| watcher | 如果不為 NULL 則會(huì)在服務(wù)器端設(shè)置監(jiān)視,當(dāng)節(jié)點(diǎn)發(fā)生變化時(shí)客戶端會(huì)得到通知。 |
| watcherCtx | 用戶指定的數(shù)據(jù),將被傳入到監(jiān)視器回調(diào)函數(shù)中,與由 zookeeper_init() 設(shè)置的全局監(jiān)視器上下文不同,該函數(shù)設(shè)置的監(jiān)視器上下文只與當(dāng)前的監(jiān)視器相關(guān)聯(lián)。 |
| strings | 返回各個(gè)子節(jié)點(diǎn)路徑。 |
| stat | 返回指定節(jié)點(diǎn)的 Stat 信息。 |
- 訪問(wèn)、設(shè)置節(jié)點(diǎn) ACL (兩個(gè))
- 獲取節(jié)點(diǎn) ACL 信息
| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| acl | 該函數(shù)所返回的指定節(jié)點(diǎn)的 ACL 信息。 |
| stat | 返回指定節(jié)點(diǎn)的 Stat 信息。 |
- 設(shè)置節(jié)點(diǎn) ACL
| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| version | 節(jié)點(diǎn)的版本號(hào)。 |
| acl | 需要設(shè)置的 ACL 信息。 |
- 批處理,即原子性地一次提交多個(gè) Zookeeper 操作。
| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| count | 提交操作的個(gè)數(shù)。 |
| ops | 包含所提交操作數(shù)組。 |
| results | 包含操作所返回結(jié)果的數(shù)組。 |
其中 zoo_op_t 是各種操作(創(chuàng)建、刪除節(jié)點(diǎn),設(shè)置節(jié)點(diǎn)數(shù)據(jù)和檢查節(jié)點(diǎn)狀態(tài)四種操作)一個(gè)封裝(聯(lián)合體),定義如下:
typedef struct zoo_op {int type;union {// CREATEstruct {const char *path;const char *data;int datalen;char *buf;int buflen;const struct ACL_vector *acl;int flags;} create_op;// DELETE struct {const char *path;int version;} delete_op;// SETstruct {const char *path;const char *data;int datalen;int version;struct Stat *stat;} set_op;// CHECKstruct {const char *path;int version;} check_op;}; } zoo_op_t;zoo_op_t 一般由以下四個(gè)函數(shù)初始化:
void zoo_create_op_init(zoo_op_t * op, const char *path, const char *value,int valuelen, const struct ACL_vector *acl,int flags, char *path_buffer, int path_buffer_len);void zoo_delete_op_init(zoo_op_t * op, const char *path, int version);void zoo_set_op_init(zoo_op_t * op, const char *path,const char *buffer, int buflen, int version,struct Stat *stat);void zoo_check_op_init(zoo_op_t * op, const char *path, int version);zoo_op_result_t 用于保存 zoo_multi 或者 zoo_amulti 返回的其中一個(gè)結(jié)果,定義如下:
typedef struct zoo_op_result {int err;char *value;int valuelen;struct Stat *stat; } zoo_op_result_t;?
以上內(nèi)容是 Zookeeper? C API 中同步 API 的介紹,如有錯(cuò)誤請(qǐng)留下您的想法和意見(jiàn),本人會(huì)盡快更正;同時(shí),我也將在后面的文章中列舉一些示例來(lái)說(shuō)明上述 API 的用法,如有興趣請(qǐng)繼續(xù)關(guān)注,如果您需要了解 Zookeeper 異步 API,請(qǐng)移步第六講《Zookeeper C API 指南六(異步 API 介紹)》。
上一講《Zookeeper C API 指南五(同步 API 介紹)》講了Zookeeper 同步 API 的分類和相關(guān)解釋,相信大家對(duì) Zookeeper 同步 API 也有了一個(gè)大致的了解,本文我會(huì)給大家介紹 Zookeeper C API 中的異步調(diào)用的函數(shù)(即以 zoo_a* 開(kāi)頭的函數(shù)),本文大致結(jié)構(gòu)與《Zookeeper C API 指南五(同步 API 介紹)》,先匯總 API,然后再分類,并對(duì)每個(gè) API 作出解釋。
在具體講解 Zookeeper 異步 API 之前,首先回顧一下《Zookeeper C API 指南三(回調(diào)函數(shù))》,除了監(jiān)視器回調(diào)函數(shù)以外,還有其他 7 種回調(diào)函數(shù),他們通常在異步 API 調(diào)用結(jié)束或 Zookeeper? 客戶端失去連接時(shí)被調(diào)用。根據(jù)回調(diào)函數(shù)返回參數(shù)(即函數(shù)的輸出參數(shù))的類型不同分為以下幾類:返回 void 類型的回調(diào)函數(shù),返回 Stat 結(jié)構(gòu)的回調(diào)函數(shù),返回字符串的回調(diào)函數(shù),返回?cái)?shù)據(jù)的回調(diào)函數(shù),返回字符串列表(a list of string)的回調(diào)函數(shù),同時(shí)返回字符串列表(a list of string)和 Stat 結(jié)構(gòu)的回調(diào)函數(shù),以及返回 ACL 信息的回調(diào)函數(shù),7 中回調(diào)函數(shù)原型聲明如下:
// 返回 void 類型的回調(diào)函數(shù) typedef void(* void_completion_t)(int rc, const void *data);// 返回 Stat 結(jié)構(gòu)的回調(diào)函數(shù) typedef void(* stat_completion_t)(int rc, const struct Stat *stat, const void *data); // 返回字符串的回調(diào)函數(shù) typedef void(* string_completion_t)(int rc, const char *value, const void *data); // 返回?cái)?shù)據(jù)的回調(diào)函數(shù) typedef void(* data_completion_t)(int rc, const char *value, int value_len, const struct Stat *stat, const void *data); // 返回字符串列表(a list of string)的回調(diào)函數(shù) typedef void(* strings_completion_t)(int rc, const struct String_vector *strings, const void *data); // 同時(shí)返回字符串列表(a list of string)和 Stat 結(jié)構(gòu)的回調(diào)函數(shù) typedef void(* strings_stat_completion_t)(int rc, const struct String_vector *strings, const struct Stat *stat, const void *data); // 以及返回 ACL 信息的回調(diào)函數(shù) typedef void(* acl_completion_t)(int rc, struct ACL_vector *acl, struct Stat *stat, const void *data);?可能這么說(shuō)還不是很理解,那么我們以異步創(chuàng)建 znode 節(jié)點(diǎn)(zoo_acreate())為例解釋一下:
zoo_acreate函數(shù)原型如下:
ZOOAPI 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);其中參數(shù) string_completion_t completion 即返回字符串的回調(diào)函數(shù),那么當(dāng) zoo_acreate 調(diào)用結(jié)束時(shí)將會(huì)觸發(fā) completion 回調(diào)函數(shù)的調(diào)用,同時(shí)傳遞給 completion 的rc 參數(shù)為: ZOK 操作完成;ZNONODE 父節(jié)點(diǎn)不存在;ZNODEEXISTS 節(jié)點(diǎn)已存在;ZNOAUTH 客戶端沒(méi)有權(quán)限創(chuàng)建節(jié)點(diǎn)。ZNOCHILDRENFOREPHEMERALS 臨時(shí)節(jié)點(diǎn)不能創(chuàng)建子節(jié)點(diǎn)。而string_completion_t completion 中 const char *value 參數(shù)即新節(jié)點(diǎn)的路徑名(注:如果 zoo_acreate 設(shè)置了ZOO_EPHEMERAL,則創(chuàng)建節(jié)點(diǎn)成功后,節(jié)點(diǎn)名稱并不是 zoo_acreate 中 path 參數(shù)所指定的名稱,而是類似與 /xyz0000000001,/xyz0000000002... 的名稱)。另外,string_completion_t completion 中 const void *data 參數(shù)即為 zoo_acreate 中的 const void *data。
一般來(lái)說(shuō),zoo_acreate 函數(shù)可以按照以下方式調(diào)用:
int ret = zoo_acreate(zkhandle, "/xyz", "hello", 5,&ZOO_OPEN_ACL_UNSAFE, 0 /* ZOO_SEQUENCE */,zktest_string_completion, "acreate");if (ret) {fprintf(stderr, "Error %d for %s\n", ret, "acreate");exit(EXIT_FAILURE);}?其中 zktest_string_completion 功能很簡(jiǎn)單,就是把創(chuàng)建成功后的節(jié)點(diǎn)名稱打印出來(lái),函數(shù)定義如下:
void zktest_string_completion(int rc, const char *name, const void *data) {fprintf(stderr, "[%s]: rc = %d\n", (char*)(data==0?"null":data), rc);if (!rc) {fprintf(stderr, "\tname = %s\n", name);} }?好了,有了上面的基礎(chǔ),我們接下來(lái)再來(lái)講講 Zookeeper 異步 API 吧 :-)
Zookeeper C API 中與訪問(wèn) Zookeeper 服務(wù)相關(guān)(比如創(chuàng)建、刪除 znode 節(jié)點(diǎn),獲取子節(jié)點(diǎn),設(shè)置 znode 數(shù)據(jù)等)的異步 API 如下:
ZOOAPI 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);ZOOAPI int zoo_adelete(zhandle_t * zh, const char *path, int version,void_completion_t completion, const void *data);ZOOAPI int zoo_aexists(zhandle_t * zh, const char *path, int watch,stat_completion_t completion, const void *data);ZOOAPI int zoo_awexists(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,stat_completion_t completion, const void *data);ZOOAPI int zoo_aget(zhandle_t * zh, const char *path, int watch,data_completion_t completion, const void *data);ZOOAPI int zoo_awget(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,data_completion_t completion, const void *data);ZOOAPI int zoo_aset(zhandle_t * zh, const char *path,const char *buffer, int buflen, int version,stat_completion_t completion, const void *data);ZOOAPI int zoo_aget_children(zhandle_t * zh, const char *path,int watch,strings_completion_t completion,const void *data);ZOOAPI int zoo_awget_children(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,strings_completion_t completion,const void *data);ZOOAPI int zoo_aget_children2(zhandle_t * zh, const char *path,int watch,strings_stat_completion_t completion,const void *data);ZOOAPI int zoo_awget_children2(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,strings_stat_completion_t completion,const void *data);ZOOAPI int zoo_async(zhandle_t * zh, const char *path,string_completion_t completion, const void *data);ZOOAPI int zoo_aget_acl(zhandle_t * zh, const char *path,acl_completion_t completion, const void *data);ZOOAPI int zoo_aset_acl(zhandle_t * zh, const char *path, int version,struct ACL_vector *acl, void_completion_t,const void *data);ZOOAPI int zoo_amulti(zhandle_t * zh, int count, const zoo_op_t * ops,zoo_op_result_t * results, void_completion_t,const void *data);本文將以上異步 API 細(xì)分為以下幾類:(1). 創(chuàng)建、刪除 znode 節(jié)點(diǎn),(2). 可設(shè)置 watch 的 API,(3). 訪問(wèn)、設(shè)置節(jié)點(diǎn) ACL 的 API,(4). 異步批處理 API。
- ?創(chuàng)建、刪除 znode 節(jié)點(diǎn)
- 創(chuàng)建 znode 節(jié)點(diǎn)
| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| value | 該節(jié)點(diǎn)保存的數(shù)據(jù)。 |
| valuelen | 該節(jié)點(diǎn)保存數(shù)據(jù)的大小。 |
| acl | 該節(jié)點(diǎn)初始 ACL,ACL 不能為null 或空。 |
| flags | 該參數(shù)可以設(shè)置為 0,或者創(chuàng)建標(biāo)識(shí)符 ZOO_EPHEMERAL,?ZOO_SEQUENCE 的組合或(OR)。 |
| completion | 當(dāng)創(chuàng)建節(jié)點(diǎn)請(qǐng)求完成時(shí)會(huì)調(diào)用該函數(shù),該函數(shù)原型詳見(jiàn)第三講《回調(diào)函數(shù)》一節(jié)。同時(shí)傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 父節(jié)點(diǎn)不存在;ZNODEEXISTS 節(jié)點(diǎn)已存在;ZNOAUTH 客戶端沒(méi)有權(quán)限創(chuàng)建節(jié)點(diǎn)。ZNOCHILDRENFOREPHEMERALS 臨時(shí)節(jié)點(diǎn)不能創(chuàng)建子節(jié)點(diǎn)。 |
| data | completion 函數(shù)被調(diào)用時(shí),傳遞給 completion 的數(shù)據(jù)。 |
- 刪除 znode 節(jié)點(diǎn)
| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| version | 期望的節(jié)點(diǎn)版本號(hào),如果真實(shí)的版本號(hào)與期望的版本號(hào)不同則 zoo_delete() 調(diào)用失敗,-1 表示不不檢查版本號(hào)。 |
| completion | 當(dāng)刪除節(jié)點(diǎn)請(qǐng)求完成時(shí)會(huì)調(diào)用該函數(shù),該函數(shù)原型詳見(jiàn)第三講《回調(diào)函數(shù)》一節(jié)。同時(shí)傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點(diǎn)不存在;ZNOAUTH 客戶端沒(méi)有權(quán)限刪除節(jié)點(diǎn);ZBADVERSION 版包號(hào)不匹配;ZNOTEMPTY 當(dāng)前節(jié)點(diǎn)存在子節(jié)點(diǎn),不能被刪除。 |
| data | completion 函數(shù)被調(diào)用時(shí),傳遞給 completion 的數(shù)據(jù)。 |
?
- 可設(shè)置 watch 的 API(exists(兩個(gè)) + get(兩個(gè)) + get_children(四個(gè)) = 八個(gè))
- 檢查節(jié)點(diǎn)狀態(tài) exists(兩個(gè),分別是 zoo_aexists() 和 zoo_awexists(),區(qū)別是后者可以指定單獨(dú)的 watcher_fn(監(jiān)視器回調(diào)函數(shù)),而前者只能用 zookeeper_init() 設(shè)置的全局監(jiān)視器回調(diào)函數(shù),同時(shí) aget 和 aget_children兩族函數(shù)也一樣,帶有zoo_w* 的函數(shù)可以指定單獨(dú)的 watcher_fn)。)
| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| watch | 如果非 0,則在服務(wù)器端設(shè)置監(jiān)視,當(dāng)節(jié)點(diǎn)發(fā)生變化時(shí)客戶端會(huì)得到通知,即使當(dāng)前指定的節(jié)點(diǎn)不存在也會(huì)設(shè)置監(jiān)視,這樣該節(jié)點(diǎn)被創(chuàng)建時(shí),客戶端也可以得到通知。 |
| completion | 當(dāng) zoo_aexists 請(qǐng)求完成時(shí)會(huì)調(diào)用該函數(shù),該函數(shù)原型詳見(jiàn)第三講《回調(diào)函數(shù)》一節(jié)。同時(shí)傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點(diǎn)不存在;ZNOAUTH 客戶端沒(méi)有權(quán)限刪除節(jié)點(diǎn)。 |
| data | completion 函數(shù)被調(diào)用時(shí),傳遞給 completion 的數(shù)據(jù)。 |
?
ZOOAPI int zoo_awexists(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,stat_completion_t completion, const void *data);| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| watcher | 如果非 0,則在服務(wù)器端設(shè)置監(jiān)視,當(dāng)節(jié)點(diǎn)發(fā)生變化時(shí)客戶端會(huì)得到通知,即使當(dāng)前指定的節(jié)點(diǎn)不存在也會(huì)設(shè)置監(jiān)視,這樣該節(jié)點(diǎn)被創(chuàng)建時(shí),客戶端也可以得到通知。 |
| watcherCtx | 用戶指定的數(shù)據(jù),將被傳入到監(jiān)視器回調(diào)函數(shù)中,與由 zookeeper_init() 設(shè)置的全局監(jiān)視器上下文不同,該函數(shù)設(shè)置的監(jiān)視器上下文只與當(dāng)前的監(jiān)視器相關(guān)聯(lián)。 |
| completion | 當(dāng)zoo_awexists 請(qǐng)求完成時(shí)會(huì)調(diào)用該函數(shù),該函數(shù)原型詳見(jiàn)第三講《回調(diào)函數(shù)》一節(jié)。同時(shí)傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點(diǎn)不存在;ZNOAUTH 客戶端沒(méi)有權(quán)限刪除節(jié)點(diǎn)。 |
| data | completion 函數(shù)被調(diào)用時(shí),傳遞給 completion 的數(shù)據(jù)。 |
?
- 獲取節(jié)點(diǎn)數(shù)據(jù) aget(兩個(gè))
| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| watch | 如果非 0,則在服務(wù)器端設(shè)置監(jiān)視,當(dāng)節(jié)點(diǎn)發(fā)生變化時(shí)客戶端會(huì)得到通知。 |
| completion | 當(dāng)zoo_aget 請(qǐng)求完成時(shí)會(huì)調(diào)用該函數(shù),該函數(shù)原型詳見(jiàn)第三講《回調(diào)函數(shù)》一節(jié)。同時(shí)傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點(diǎn)不存在;ZNOAUTH 客戶端沒(méi)有權(quán)限刪除節(jié)點(diǎn)。 |
| data | completion 函數(shù)被調(diào)用時(shí),傳遞給 completion 的數(shù)據(jù)。 |
?
ZOOAPI int zoo_awget(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,data_completion_t completion, const void *data);| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| watcher | 如果非 0,則在服務(wù)器端設(shè)置監(jiān)視,當(dāng)節(jié)點(diǎn)發(fā)生變化時(shí)客戶端會(huì)得到通知,即使當(dāng)前指定的節(jié)點(diǎn)不存在也會(huì)設(shè)置監(jiān)視,這樣該節(jié)點(diǎn)被創(chuàng)建時(shí),客戶端也可以得到通知。 |
| watcherCtx | 用戶指定的數(shù)據(jù),將被傳入到監(jiān)視器回調(diào)函數(shù)中,與由 zookeeper_init() 設(shè)置的全局監(jiān)視器上下文不同,該函數(shù)設(shè)置的監(jiān)視器上下文只與當(dāng)前的監(jiān)視器相關(guān)聯(lián)。 |
| completion | 當(dāng)zoo_awget 請(qǐng)求完成時(shí)會(huì)調(diào)用該函數(shù),該函數(shù)原型詳見(jiàn)第三講《回調(diào)函數(shù)》一節(jié)。同時(shí)傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點(diǎn)不存在;ZNOAUTH 客戶端沒(méi)有權(quán)限刪除節(jié)點(diǎn)。 |
| data | completion 函數(shù)被調(diào)用時(shí),傳遞給 completion 的數(shù)據(jù)。 |
?
- 獲取子節(jié)點(diǎn)列表 aget_children (四個(gè))
| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| watch | 如果非 0,則在服務(wù)器端設(shè)置監(jiān)視,當(dāng)節(jié)點(diǎn)發(fā)生變化時(shí)客戶端會(huì)得到通知。 |
| completion | 當(dāng) zoo_aget_children 請(qǐng)求完成時(shí)會(huì)調(diào)用該函數(shù),該函數(shù)原型詳見(jiàn)第三講《回調(diào)函數(shù)》一節(jié)。同時(shí)傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點(diǎn)不存在;ZNOAUTH 客戶端沒(méi)有權(quán)限刪除節(jié)點(diǎn)。 |
| data | completion 函數(shù)被調(diào)用時(shí),傳遞給 completion 的數(shù)據(jù)。 |
?
ZOOAPI int zoo_awget_children(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,strings_completion_t completion,const void *data);| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| watcher | 如果非 0,則在服務(wù)器端設(shè)置監(jiān)視,當(dāng)節(jié)點(diǎn)發(fā)生變化時(shí)客戶端會(huì)得到通知,即使當(dāng)前指定的節(jié)點(diǎn)不存在也會(huì)設(shè)置監(jiān)視,這樣該節(jié)點(diǎn)被創(chuàng)建時(shí),客戶端也可以得到通知。 |
| watcherCtx | 用戶指定的數(shù)據(jù),將被傳入到監(jiān)視器回調(diào)函數(shù)中,與由 zookeeper_init() 設(shè)置的全局監(jiān)視器上下文不同,該函數(shù)設(shè)置的監(jiān)視器上下文只與當(dāng)前的監(jiān)視器相關(guān)聯(lián)。 |
| completion | 當(dāng)zoo_awget_children 請(qǐng)求完成時(shí)會(huì)調(diào)用該函數(shù),該函數(shù)原型詳見(jiàn)第三講《回調(diào)函數(shù)》一節(jié)。同時(shí)傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點(diǎn)不存在;ZNOAUTH 客戶端沒(méi)有權(quán)限刪除節(jié)點(diǎn)。 |
| data | completion 函數(shù)被調(diào)用時(shí),傳遞給 completion 的數(shù)據(jù)。 |
?
ZOOAPI int zoo_aget_children2(zhandle_t * zh, const char *path,int watch,strings_stat_completion_t completion,const void *data);| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| watch | 如果非 0,則在服務(wù)器端設(shè)置監(jiān)視,當(dāng)節(jié)點(diǎn)發(fā)生變化時(shí)客戶端會(huì)得到通知。 |
| completion | 當(dāng) zoo_aget_children2 請(qǐng)求完成時(shí)會(huì)調(diào)用該函數(shù),該函數(shù)原型詳見(jiàn)第三講《回調(diào)函數(shù)》一節(jié)。同時(shí)傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點(diǎn)不存在;ZNOAUTH 客戶端沒(méi)有權(quán)限刪除節(jié)點(diǎn)。 |
| data | completion 函數(shù)被調(diào)用時(shí),傳遞給 completion 的數(shù)據(jù)。 |
?
ZOOAPI int zoo_awget_children2(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,strings_stat_completion_t completion,const void *data);| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| watcher | 如果非 0,則在服務(wù)器端設(shè)置監(jiān)視,當(dāng)節(jié)點(diǎn)發(fā)生變化時(shí)客戶端會(huì)得到通知,即使當(dāng)前指定的節(jié)點(diǎn)不存在也會(huì)設(shè)置監(jiān)視,這樣該節(jié)點(diǎn)被創(chuàng)建時(shí),客戶端也可以得到通知。 |
| watcherCtx | 用戶指定的數(shù)據(jù),將被傳入到監(jiān)視器回調(diào)函數(shù)中,與由 zookeeper_init() 設(shè)置的全局監(jiān)視器上下文不同,該函數(shù)設(shè)置的監(jiān)視器上下文只與當(dāng)前的監(jiān)視器相關(guān)聯(lián)。 |
| completion | 當(dāng)zoo_awget_children2 請(qǐng)求完成時(shí)會(huì)調(diào)用該函數(shù),該函數(shù)原型詳見(jiàn)第三講《回調(diào)函數(shù)》一節(jié)。同時(shí)傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點(diǎn)不存在;ZNOAUTH 客戶端沒(méi)有權(quán)限刪除節(jié)點(diǎn)。 |
| data | completion 函數(shù)被調(diào)用時(shí),傳遞給 completion 的數(shù)據(jù)。 |
?
- 訪問(wèn)、設(shè)置節(jié)點(diǎn) ACL 的 API
- 訪問(wèn)節(jié)點(diǎn) ACL
| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| completion | 當(dāng) zoo_aget_acl 請(qǐng)求完成時(shí)會(huì)調(diào)用該函數(shù),該函數(shù)原型詳見(jiàn)第三講《回調(diào)函數(shù)》一節(jié)。同時(shí)傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點(diǎn)不存在;ZNOAUTH 客戶端沒(méi)有權(quán)限刪除節(jié)點(diǎn)。 |
| data | completion 函數(shù)被調(diào)用時(shí),傳遞給 completion 的數(shù)據(jù)。 |
?
- 設(shè)置節(jié)點(diǎn) ACL
| zh | zookeeper_init() 返回的 zookeeper 句柄。 |
| path | 節(jié)點(diǎn)路徑。 |
| buffer | 保存需要設(shè)置的 ACL。 |
| buflen | buffer 的長(zhǎng)度。 |
| completion | 當(dāng) zoo_aset_acl 請(qǐng)求完成時(shí)會(huì)調(diào)用該函數(shù),該函數(shù)原型詳見(jiàn)第三講《回調(diào)函數(shù)》一節(jié)。同時(shí)傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點(diǎn)不存在;ZNOAUTH 客戶端沒(méi)有權(quán)限刪除節(jié)點(diǎn);ZINVALIDACL 非法 ACL;ZBADVERSION 版本號(hào)不匹配。 |
| data | completion 函數(shù)被調(diào)用時(shí),傳遞給 completion 的數(shù)據(jù)。 |
?
- 異步批處理 API
異步批處理與同步批處理方式類似見(jiàn)《Zookeeper C API 指南五(同步 API 介紹)》,只是需要額外設(shè)置一個(gè) void_completion_t 回調(diào)函數(shù),在此不再贅述。
?
以上內(nèi)容是 Zookeeper? C API 中異步 API 的介紹,如有錯(cuò)誤請(qǐng)留下您的想法和意見(jiàn),我會(huì)盡快更正;同時(shí),我也將在后面的文章中列舉一些示例來(lái)說(shuō)明上述 API 的用法,如有興趣請(qǐng)繼續(xù)關(guān)注。
在前面的文章中我們講了大部分 Zookeeper? C API,相信大家已經(jīng)知道怎樣使用 Zookeeper? C API了吧。我曾在《Zookeeper C API 指南》系列文章的第四篇《Zookeeper C API 指南四(C API 概覽)》中也 Zookeeper C API 的分為了 5 類,他們分別是:(1)、初始化、銷毀 Zookeeper 句柄,(2)、與 zoo_multi() 和 zoo_amulti() 批量操作相關(guān)的 zoo_op_t 初始化函數(shù),(3)、同步 API,(4)、異步 API,(5)、輔助函數(shù)。其中“(1)、初始化、銷毀 Zookeeper 句柄”已經(jīng)在《Zookeeper C API 指南四(C API 概覽)》中介紹過(guò)了,并且在《Zookeeper C API 指南五(同步 API 介紹)》和《Zookeeper C API 指南六(異步 API 介紹)》中我們又分別講了“同步 API” 和 “異步 API”(其中也簡(jiǎn)單地介紹了一下與 zoo_multi() 和 zoo_amulti() 批量操作相關(guān)的 zoo_op_t 初始化函數(shù)),所以接下來(lái)我們?cè)賮?lái)講講 Zookeeper C API 中的 “輔助函數(shù)”。
我們分類的 Zookeeper C API 中輔助函數(shù)如下:
ZOOAPI void zoo_set_debug_level(ZooLogLevel logLevel);ZOOAPI void zoo_set_log_stream(FILE * logStream);ZOOAPI const clientid_t *zoo_client_id(zhandle_t * zh);ZOOAPI int zoo_recv_timeout(zhandle_t * zh);ZOOAPI const void *zoo_get_context(zhandle_t * zh);ZOOAPI void zoo_set_context(zhandle_t * zh, void *context);ZOOAPI watcher_fn zoo_set_watcher(zhandle_t * zh, watcher_fn newFn);ZOOAPI struct sockaddr *zookeeper_get_connected_host(zhandle_t * zh, struct sockaddr*addr,socklen_t * addr_len);ZOOAPI int zookeeper_interest(zhandle_t * zh, int *fd, int *interest,struct timeval *tv);ZOOAPI int zookeeper_process(zhandle_t * zh, int events);ZOOAPI int zoo_state(zhandle_t * zh);ZOOAPI const char *zerror(int c);ZOOAPI int is_unrecoverable(zhandle_t * zh);ZOOAPI void zoo_deterministic_conn_order(int yesOrNo);下面我們來(lái)講講其中比較常用的幾個(gè)函數(shù)吧 :-)
- ?設(shè)置日志等級(jí)
其中 logLevel 可以是ZOO_LOG_LEVEL_ERROR, ZOO_LOG_LEVEL_WARN,ZOO_LOG_LEVEL_INFO, ZOO_LOG_LEVEL_DEBUG四個(gè)取值。
?
- 設(shè)置日志流
Zookeeper C API 默認(rèn)的日志流是標(biāo)準(zhǔn)輸出,可以通過(guò)該函數(shù)設(shè)置 Zookeeper C API的日志流為文件。
?
- 獲取客戶端的 session id,只有在客戶端的當(dāng)前連接狀態(tài)有效時(shí)才可以。
?
- 返回當(dāng)前會(huì)話的超時(shí)時(shí)間,只有在客戶端的當(dāng)前連接狀態(tài)有效時(shí)才可以。
?
- 獲取 Zookeeper 句柄的上下文。
?
- 設(shè)置 Zookeeper 句柄的上下文。
?
- 設(shè)置 Zookeeper 句柄的全局監(jiān)視器回調(diào)函數(shù),該函數(shù)返回全局監(jiān)視器的舊回調(diào)函數(shù)。
?
- 返回當(dāng)前 Zookeeper 連接的套接字地址。
?
- 獲取當(dāng)前 Zookeeper 連接狀態(tài)。
?
- 返回某一錯(cuò)誤碼的字符串表示。
?
- 檢查當(dāng)前 Zookeeper 連接是否為不可恢復(fù)的,如果不可恢復(fù),則客戶端需要關(guān)閉連接,然后重連。
?
好了,Zookeeper 大部分的輔助函數(shù)就介紹到這里了,大家可以更多文檔可以在 zookeeper.h 中找到。:-)
前面七講我們基本上介紹完了 Zookeeper C API 的所有內(nèi)容,本文將結(jié)合一個(gè)小例子講講如何在你的實(shí)際項(xiàng)目中使用 Zookeeper 服務(wù)。
設(shè)想如下場(chǎng)景:
假設(shè)程序 A 需要 7* 24 小時(shí)在線對(duì)外提供服務(wù),但是 A 程序在生產(chǎn)環(huán)境下總是不穩(wěn)定,時(shí)常崩潰,不過(guò)幸運(yùn)的是解決方案很簡(jiǎn)單,在 A 程序崩潰以后只需要重啟它就可以了。當(dāng)然如此簡(jiǎn)單的問(wèn)題你可以提出多種解決方案,比方說(shuō)自己實(shí)現(xiàn)一個(gè)服務(wù)程序,每隔一定時(shí)間去輪詢 A 的狀態(tài),如果發(fā)現(xiàn) A 崩潰了,立即重啟它,并向管理人員報(bào)告問(wèn)題。不過(guò)我們并不打算這么做,畢竟本文主題是講 Zookeeper C API 的應(yīng)用,所以我們采用 Zookeeper 服務(wù)來(lái)解決該問(wèn)題。
若采用 Zookeeper 服務(wù)可以按照如下方案解決問(wèn)題,程序 A 在啟動(dòng)時(shí)創(chuàng)建一個(gè)臨時(shí)(ZOO_EPHEMERAL) znode 節(jié)點(diǎn) /A,然后按照正常流程對(duì)外提供服務(wù)。另外監(jiān)控程序?qū)?/A 節(jié)點(diǎn)設(shè)置監(jiān)視,當(dāng) /A 節(jié)點(diǎn)消失(說(shuō)明 A 程序已經(jīng)崩潰)時(shí),重啟 A 程序。假設(shè) A 的名稱是 QueryServer,即對(duì)外提供查詢服務(wù)的程序,具體提供什么查詢服務(wù)由應(yīng)用自身決定,我們這里只是簡(jiǎn)單地模擬一下。QueryServer 在啟動(dòng)時(shí)創(chuàng)建一個(gè) /QueryServer 的臨時(shí)節(jié)點(diǎn)(ZOO_EPHEMERAL),然后,程序 QueryServerd 監(jiān)控 /QueryServer 節(jié)點(diǎn),當(dāng) /QueryServer 節(jié)點(diǎn)消失(說(shuō)明 A 程序已經(jīng)崩潰)時(shí),重啟?QueryServer 程序。
下面是 QueryServer 的實(shí)現(xiàn)代碼:
/** =============================================================================** Filename: QueryServer.c** Description: QueryServer** Created: 02/15/2013 08:48:49 PM** Author: Fu Haiping (forhappy), haipingf@gmail.com* Company: ICT ( Institute Of Computing Technology, CAS )** =============================================================================*/ #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <zookeeper/zookeeper.h> #include <zookeeper/zookeeper_log.h>void QueryServer_watcher_g(zhandle_t* zh, int type, int state,const char* path, void* watcherCtx) {if (type == ZOO_SESSION_EVENT) {if (state == ZOO_CONNECTED_STATE) {printf("[[[QueryServer]]] Connected to zookeeper service successfully!\n");} else if (state == ZOO_EXPIRED_SESSION_STATE) { printf("Zookeeper session expired!\n");}} }void QueryServer_string_completion(int rc, const char *name, const void *data) {fprintf(stderr, "[%s]: rc = %d\n", (char*)(data==0?"null":data), rc);if (!rc) {fprintf(stderr, "\tname = %s\n", name);} }void QueryServer_accept_query() {printf("QueryServer is running...\n"); }int main(int argc, const char *argv[]) {const char* host = "127.0.0.1:2181,127.0.0.1:2182,""127.0.0.1:2183,127.0.0.1:2184,127.0.0.1:2185";int timeout = 30000;zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);zhandle_t* zkhandle = zookeeper_init(host,QueryServer_watcher_g, timeout, 0, "hello zookeeper.", 0);if (zkhandle == NULL) {fprintf(stderr, "Error when connecting to zookeeper servers...\n");exit(EXIT_FAILURE);}// struct ACL ALL_ACL[] = {{ZOO_PERM_ALL, ZOO_ANYONE_ID_UNSAFE}};// struct ACL_vector ALL_PERMS = {1, ALL_ACL};int ret = zoo_acreate(zkhandle, "/QueryServer", "alive", 5,&ZOO_OPEN_ACL_UNSAFE, ZOO_EPHEMERAL,QueryServer_string_completion, "zoo_acreate");if (ret) {fprintf(stderr, "Error %d for %s\n", ret, "acreate");exit(EXIT_FAILURE);}do {// 模擬 QueryServer 對(duì)外提供服務(wù).// 為了簡(jiǎn)單起見(jiàn), 我們?cè)诖苏{(diào)用一個(gè)簡(jiǎn)單的函數(shù)來(lái)模擬 QueryServer.// 然后休眠 5 秒,程序主動(dòng)退出(即假設(shè)此時(shí)已經(jīng)崩潰). QueryServer_accept_query();sleep(5);} while(false);zookeeper_close(zkhandle); }Makefile如下:
all:QueryServerQueryServer:QueryServer.ogcc -L/usr/local/lib/ -lzookeeper_mt -o $@ $^ QueryServer.o:QueryServer.cgcc -DTHREADED -I/usr/local/include/zookeeper -o $@ -c $^.PHONY:cleanclean:rm QueryServer.o QueryServer?
QueryServerd 代碼如下:
/** =============================================================================** Filename: QueryServerd.c** Description: QueryServer daemon using zookeeper. ** Created: 02/15/2013 08:48:49 PM** Author: Fu Haiping (forhappy), haipingf@gmail.com* Company: ICT ( Institute Of Computing Technology, CAS )** =============================================================================*/ #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <zookeeper/zookeeper.h> #include <zookeeper/zookeeper_log.h>void QueryServerd_watcher_global(zhandle_t * zh, int type, int state,const char *path, void *watcherCtx); static void QueryServerd_dump_stat(const struct Stat *stat); void QueryServerd_stat_completion(int rc, const struct Stat *stat,const void *data); void QueryServerd_watcher_awexists(zhandle_t *zh, int type, int state,const char *path, void *watcherCtx); static void QueryServerd_awexists(zhandle_t *zh);void QueryServerd_watcher_global(zhandle_t * zh, int type, int state,const char *path, void *watcherCtx) {if (type == ZOO_SESSION_EVENT) {if (state == ZOO_CONNECTED_STATE) {printf("Connected to zookeeper service successfully!\n");} else if (state == ZOO_EXPIRED_SESSION_STATE) { printf("Zookeeper session expired!\n");}} }static void QueryServerd_dump_stat(const struct Stat *stat) {char tctimes[40];char tmtimes[40];time_t tctime;time_t tmtime;if (!stat) {fprintf(stderr, "null\n");return;}tctime = stat->ctime / 1000;tmtime = stat->mtime / 1000;ctime_r(&tmtime, tmtimes);ctime_r(&tctime, tctimes);fprintf(stderr, "\tctime = %s\tczxid=%llx\n""\tmtime=%s\tmzxid=%llx\n""\tversion=%x\taversion=%x\n""\tephemeralOwner = %llx\n",tctimes, stat->czxid,tmtimes, stat->mzxid,(unsigned int) stat->version, (unsigned int) stat->aversion,stat->ephemeralOwner); }void QueryServerd_stat_completion(int rc, const struct Stat *stat,const void *data) {// fprintf(stderr, "%s: rc = %d Stat:\n", (char *) data, rc);// QueryServerd_dump_stat(stat); }void QueryServerd_watcher_awexists(zhandle_t *zh, int type, int state,const char *path, void *watcherCtx) {if (state == ZOO_CONNECTED_STATE) {if (type == ZOO_DELETED_EVENT) {printf("QueryServer gone away, restart now...\n");// re-exists and set watch on /QueryServer again. QueryServerd_awexists(zh);pid_t pid = fork();if (pid < 0) {fprintf(stderr, "Error when doing fork.\n");exit(EXIT_FAILURE);}if (pid == 0) { /* child process */// 重啟 QueryServer 服務(wù).execl("/tmp/QueryServer/QueryServer", "QueryServer", NULL);exit(EXIT_SUCCESS);}sleep(1); /* sleep 1 second for purpose. */} else if (type == ZOO_CREATED_EVENT) {printf("QueryServer started...\n");}}// re-exists and set watch on /QueryServer again. QueryServerd_awexists(zh); }static void QueryServerd_awexists(zhandle_t *zh) {int ret =zoo_awexists(zh, "/QueryServer",QueryServerd_watcher_awexists,"QueryServerd_awexists.",QueryServerd_stat_completion,"zoo_awexists");if (ret) {fprintf(stderr, "Error %d for %s\n", ret, "aexists");exit(EXIT_FAILURE);} }int main(int argc, const char *argv[]) {const char *host = "127.0.0.1:2181,127.0.0.1:2182,""127.0.0.1:2183,127.0.0.1:2184,127.0.0.1:2185";int timeout = 30000;zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);zhandle_t *zkhandle = zookeeper_init(host,QueryServerd_watcher_global,timeout,0, "QueryServerd", 0);if (zkhandle == NULL) {fprintf(stderr, "Error when connecting to zookeeper servers...\n");exit(EXIT_FAILURE);}QueryServerd_awexists(zkhandle);// Wait for asynchronous zookeeper call done. getchar();zookeeper_close(zkhandle);return 0; }?
Makefile 如下:
all:QueryServerdQueryServerd:QueryServerd.ogcc -L/usr/local/lib/ -lzookeeper_mt -o $@ $^ QueryServerd.o:QueryServerd.cgcc -g -DTHREADED -I/usr/local/include/zookeeper -o $@ -c $^.PHONY:cleanclean:rm QueryServerd.o QueryServerd?
首先執(zhí)行 QueryServerd,
forhappy@haiping-ict:/tmp/QueryServerd$ ./QueryServerd Connected to zookeeper service successfully!然后執(zhí)行 QueryServer,
forhappy@haiping-ict:/tmp/QueryServer$ ./QueryServer QueryServer is running... [[[QueryServer]]] Connected to zookeeper service successfully! [zoo_acreate]: rc = 0name = /QueryServer可見(jiàn) Queryerver 創(chuàng)建了 /QueryServer 節(jié)點(diǎn),5 秒后 QueryServer 模擬程序崩潰而退出,那么此時(shí)在 QueryServerd 端輸出如下:
Connected to zookeeper service successfully! QueryServer started... # QueryServerd 感知到 QueryServer 已正常啟動(dòng). QueryServer gone away, restart now... # 5 秒鐘后,QueryServer 崩潰,QueryServerd 準(zhǔn)備重啟 QueryServer. QueryServer is running... #?QueryServer 正在運(yùn)行,以下 3 行是 QueryServer 輸出結(jié)果。 [[[QueryServer]]] Connected to zookeeper service successfully! [zoo_acreate]: rc = 0name = /QueryServer QueryServer started... #?QueryServerd 感知到 QueryServer 已正常啟動(dòng). QueryServer gone away, restart now...# 又過(guò)了 5 秒鐘后,QueryServer 崩潰,QueryServerd 準(zhǔn)備重啟 QueryServer. QueryServer is running... #?QueryServer 再次運(yùn)行,以下 3 行是 QueryServer 輸出結(jié)果。 [[[QueryServer]]] Connected to zookeeper service successfully! [zoo_acreate]: rc = 0name = /QueryServer QueryServer started... #?QueryServerd 再次感知到 QueryServer 已正常啟動(dòng),如此反復(fù). QueryServer gone away, restart now... QueryServer is running... [[[QueryServer]]] Connected to zookeeper service successfully! [zoo_acreate]: rc = 0name = /QueryServer QueryServer started...即 QueryServer 每 5 秒鐘崩潰一次,然后又被 QueryServerd 重啟,模擬了上面的應(yīng)用場(chǎng)景。
好了 Zookeeper C API 的應(yīng)用小示例講完了,可能應(yīng)用場(chǎng)景選取的不好,不過(guò)大致可以一些說(shuō)明問(wèn)題吧,如果你想看 Zookeeper 更貼近現(xiàn)實(shí)的應(yīng)用場(chǎng)景,可以參考淘寶的一篇文章《ZooKeeper典型應(yīng)用場(chǎng)景一覽》和 IBM developerWorks 的一篇博文《分布式服務(wù)框架 Zookeeper -- 管理分布式環(huán)境中的數(shù)據(jù)》。
總結(jié)
以上是生活随笔為你收集整理的Zookeeper C API 指南的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: libuv 中文编程指南
- 下一篇: 统计一下你写过多少代码