zookeeper系列之异步通知模式-Watcher
1 watcher种类和事件种类
1. zookeeper实例化时注入的默认Watcher
2. dataWatchers 一个Map<string Set<Watcher>>数据结构,保存调用getData时 注入的Watcher或者调用exist时path指定的节点存在
3. existWatchers 一个Map<string Set<Watcher>>数据结构,保存调用exits时对应的path节点不存在条件下注入的Watcher
4. childWatchers一个Map<string Set<Watcher>>数据结构,保存调用getChildren 时注入的Watcher
默认Watcher主要是处理连接建立成功,连接断了-会重连,SESSION失效-这个需要重新实例zookeeper对象这些事件
其他的三个Watcher都是MAP<String, SET<Watcher>>结构的,MAP中的KEY是zookeeper数据路径,当调用
exists,getData,getChildren函数时会需要传入一个Watcher,对应的path上的数据发生改变时,zookeeper服务器
会发送NOTIFY包给客户端,客户端在收到NOTIFY包后根据包指明的path和事件类别回调有关Watcher的process函数。
所有需要系统的管理这些Watcher,故分成三个MAP来管理这些Watcher。
当调用getData时将注入的Watcher加入到dataWatchers.get(path)的SET里面,调用childWatchers时一样。需要
重点注意的是当调用exists时,如果path不存在则加入到existWatchers.get(path)的SET里面,否则加入到
dataWatchers.get(path)的SET里面,这样做的原因是为了保持和客户端接收到NOTIFY包时处理一致。
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
zookeeper系列之异步通知模式-Watcher的更多相关文章
- zookeeper系列之:独立模式部署zookeeper服务
一.简述 独立模式是部署zookeeper服务的三种模式中最简单和最基础的模式,只需一台机器即可,独立模式仅适用于学习,开发和生产都不建议使用独立模式.本文介绍以独立模式部署zookeeper服务器的 ...
- Linux通信之异步通知模式
[参考]韦东山 教学笔记 为了使设备支持异步通知机制,驱动程序中涉及以下3项工作:1. 支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应进程ID. 不过此项工 ...
- arm驱动linux异步通知与异步IO【转】
转自:http://blog.csdn.net/chinazhangzhong123/article/details/51638793 <[ arm驱动] linux异步通知与 异步IO> ...
- Smart20学习记录----异步通知
异步通知: 阻塞与非阻塞访问.poll()函数提供了较好地解决设备访问的机制(应用程序主动访问) 异步通知:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件 ...
- linux异步通知
简述 linux下异步方式有两种:异步通知和异步IO(AIO),aio请参考:linux异步IO--aio 异步通知的含义是:一旦设备就绪,则主动通知应用程序,这样应用程序就不需要查询设备状态,准确称 ...
- Linux内核开发之异步通知与异步I/O(一)
“小王,听说过锦上添花吧..”我拍拍下王的头说. “还锦上添花你,为你上次提的几个东东,我是头上长包..”小王气愤地瞪着我. “啊,为啥这样呢,本来还特意拒绝了MM的月份,抽出时间打算给你说点高级的东 ...
- 异步通知与异步I/O
异步通知:很简单,一旦设备准备好,就主动通知应用程序,这种情况下应用程序就不需要查询设备状态,这是不是特像硬件上常提的"中断的概念".上边比较准确的说法其实应该叫做"信号 ...
- 关于 exynos 4412 按键中断 异步通知
以下是驱动测试代码: //内核的驱动代码 #include <linux/init.h> #include <linux/module.h> //for module_init ...
- linux 设备驱动与应用程序异步通知
一.异步通知机制简介 异步通知机制的意思:一旦设备准备就绪,可以主动的通知应用程序进行相应的操作,从而使得应用程序不必去查询设备的状态. 异步通知比较准确的称谓是"信号驱动的异步IO&quo ...
随机推荐
- <marquee>,视频和音频的插入,正则表达式
1.marquee 页面的自动滚动效果,不仅可以移动文字,也可以移动图片表格. <marquee></marquee>之间加内容即可. marquee的属性 1.滚动方向dir ...
- Linux 配置脚本 启动服务
之前在mac安装了php和nginx每次都用一堆命令重启 今天没事情干,心血来潮,自己研究写了一段shell脚本来重启 首先vim /usr/sbin/pn 代码如下 #! /bin/bash php ...
- nginx优化缓冲缓存
反向代理的一个问题是代理大量用户时会增加服务器进程的性能冲击影响.在大多数情况下,可以很大程度上能通过利用Nginx的缓冲和缓存功能减轻. 当代理到另一台服务器,两个不同的连接速度会影响客户的体验: ...
- photoshop移动工具
1*移动工具 V 移动图层 若果移动选区相当于剪切 2*
- Jmeter的优点是什么?除了轻量级,它和LoadRunner有什么本质区别
1.jmeter的架构和loadrunner原理一样,都是通过中间代理,监控和收集并发客户端发出的指令,把他们生成脚本,再发送到应用服务器,再监控服务器反馈结果的一个过程: 2.分布式中间代理功能在j ...
- FZU 2086 餐厅点餐(枚举)
///个人感觉vector好看一点 #include<iostream> #include<cstdio> #include<cstring> #include&l ...
- HDU 5741 Helter Skelter
离线处理+扫描线.题意很容易转化:若干个矩形形成并集,询问一些点是否在并集中? 官方题解不是这样做的....那种做法效率更高,暂时还不会.我这样是4500ms G++过的,C++TLE...... 区 ...
- Oracle数据库设计小细节
1. 如果使用PowerDesigner此类工具,注意将工具的导出的SQL语句中对于表的双引号去掉. 2. 建表和建字段的时候,不同单词之间使用下划线分隔,比如 REC_ID 3. Oracle中数值 ...
- JS中三目运算符和if else的区别分析与示例
本文是通过示例详细分析了JS中三目运算符和if else的区别,是篇非常不错的文章,这里推荐给大家. 今天写了一个图片轮播的小demo,用到了判断 先试了一下if else,代码如下: 复制代码代 ...
- 解决:无法将“Add-Migration”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次
1.输入的中划线“-”格式不对,检查是否为全角状态下输入,误输入了下划线“_",或是前后有空格: 2.没有引用EntityFramework命令,请执行如下名称(Import-Module ...