zookeeper系列之非同步通知模式-Watcher
Watch事件型別:
ZOO_CREATED_EVENT:節點建立事件,需要watch一個不存在的節點,當節點被建立時觸發,此watch通過zoo_exists()設定
ZOO_DELETED_EVENT:節點刪除事件,此watch通過zoo_exists()或zoo_get()設定
ZOO_CHANGED_EVENT:節點資料改變事件,此watch通過zoo_exists()或zoo_get()設定
ZOO_CHILD_EVENT:子節點列表改變事件,此watch通過zoo_get_children()或zoo_get_children2()設定
ZOO_SESSION_EVENT:會話失效事件,客戶端與服務端斷開或重連時觸發
ZOO_NOTWATCHING_EVENT:watch移除事件,服務端出於某些原因不再為客戶端watch節點時觸發
watch事件與zookeeper讀操作的對應關係圖:
2 watcher api
Watcher是Zookeeper用來實現distribute lock, distribute configure, distribute queue等應用的主要手段。要監控data_tree上的任何節點的變化(節點本身的增加,刪除,資料修改,以及孩子的變化)都可以在獲取該資料時註冊一個Watcher,這有很像Listener模式。一旦該節點資料變化,Follower會發送一個notification response,client收到notification響應,則會查詢對應的Watcher並回調他們。 有以下介面可以註冊Watcher:
1. Stat exists(final String path, Watcher watcher)
2. Stat exists(String path, boolean watch)
3. void exists(String path, boolean watch, StatCallback cb, Object ctx)
4. void exists(final String path, Watcher watcher, StatCallback cb, Object ctx)
5. byte[] getData(final String path, Watcher watcher, Stat stat)
6. byte[] getData(String path, boolean watch, Stat stat)
7. void getData(final String path, Watcher watcher, DataCallback cb, Object ctx)
8. void getData(String path, boolean watch, DataCallback cb, Object ctx)
9. List<string> getChildren(final String path, Watcher watcher)
10. List<string> getChildren(String path, boolean watch)
11. void getChildren(final String path, Watcher watcher,ChildrenCallback cb, Object ctx)
如果引數需要傳遞watcher,則可以自己定義Watcher進行回撥處理。如果是Boolean型變數,當為true時,則使用系統預設的Watcher,系統預設的Watcher是在zookeeper的建構函式中傳遞的Watcher。如果Watcher為空或者Boolean變數時為false,則表明不註冊Watcher。如果獲取資料後不需要關注該資料是否變化,就不需要註冊Watcher。上面沒有返回值的都是非同步呼叫模式。需要注意的是,一旦Watcher被呼叫後,將會從map中刪除,如果還需要關注資料的變化,需要再次註冊。 Watcher原理 要搞清楚Watcher的原理,讓我們看看Watcher的工作流程。
Watcher的使用與注意事項
Watcher需要每次都要註冊。
並不是Watcher的節點被修改n次,客戶端註冊就會被通知n次。如果watcher的節點頻繁被修改,有可能修改了10次,客戶端被通知8次。如果client與server連線狀態發生改變,watcher總是會被通知。
3 一個例子
#include <string.h> #include <errno.h> #include "zookeeper.h" static zhandle_t *zh; /** * In this example this method gets the cert for your * environment -- you must provide */ char *foo_get_cert_once(char* id) { return 0; } /** Watcher function -- empty for this example, not something you should * do in real code */ void watcher(zhandle_t *zzh, int type, int state, const char *path, void *watcherCtx) {} int main(int argc, char argv) { char buffer[512]; char p[2048]; char *cert=0; char appId[64]; strcpy(appId, "example.foo_test"); cert = foo_get_cert_once(appId); if(cert!=0) { fprintf(stderr, "Certificate for appid [%s] is [%s]\n",appId,cert); strncpy(p,cert, sizeof(p)-1); free(cert); } else { fprintf(stderr, "Certificate for appid [%s] not found\n",appId); strcpy(p, "dummy"); } zoo_set_debug_level(ZOO_LOG_LEVEL_DEBUG); zh = zookeeper_init("localhost:3181", watcher, 10000, 0, 0, 0); if (!zh) { return errno; } if(zoo_add_auth(zh,"foo",p,strlen(p),0,0)!=ZOK) return 2; struct ACL CREATE_ONLY_ACL[] = {{ZOO_PERM_CREATE, ZOO_AUTH_IDS}}; struct ACL_vector CREATE_ONLY = {1, CREATE_ONLY_ACL}; int rc = zoo_create(zh,"/xyz","value", 5, &CREATE_ONLY, ZOO_EPHEMERAL, buffer, sizeof(buffer)-1); /** this operation will fail with a ZNOAUTH error */ int buflen= sizeof(buffer); struct Stat stat; rc = zoo_get(zh, "/xyz", 0, buffer, &buflen, &stat); if (rc) { fprintf(stderr, "Error %d for %s\n", rc, __LINE__); } zookeeper_close(zh); return 0; }
轉自:http://zoutm.iteye.com/blog/708468