确保zookeeper一定收到通知消息的方法

zookeeper能够同步同步各节点的znode数据,client可以使用getChildren,getData,exists方法在znode tree路径上设置watch,当watch路径上发生节点create、delete、update的时候,会通知到client。client可以得到通知后,再获取数据,执行业务逻辑操作。

但是因为没有消息接收后的确认机制,这个通知机制是不可靠的,也就是说znode的修改者并不知道是否所有的client都被通知到了,或者说client也不知道自己是否错过了哪些通知消息。这种现象可能由网络原因引起,也可能是client刚触发了watch事件,还没有来得及重新设置watch,下个事件就发生了(zookeeper只提供了一次性watch)。

在笔者的使用场景中,这是有问题的。在我们分布式配置管理的场景中,有3份配置副本,管理节点本地数据库中有一份,zookeeper中保存了一份,使用配置的软件引擎进程中保存了一份。当下发配置时,是需要全部软件引擎都生效最新的配置,而如果有某个引擎错过了通知,那么就会漏掉某个配置,导致问题,而到底谁没有成功生效,这些节点都不知道,甚至错过通知的节点自身也不知道。

因此我提出一种设计,至少让错过通知的节点自身知道错过了消息,并采取主动同步配置的方式,来补救。这样能够保证,配置下发后,至少一段时间后所有软件引擎的都使用了最新的配置。

这利用了zookeeper自身的几个特性:

1)zookeeper维护一个全局的操作id,zxid,每一个create,delete,update操作都会使该id加1。

2)zookeeper为每个路径(znode)节点都保存了它的修改版本dataversion,和最新一次修改zxid——mzxid。

3)zookeeper保证每个client连接的session中,看到的通知顺序与这些事件发生的先后顺序是严格一致的。

我们来假设要在/group/policy下增加、删除、修改配置,每个配置有1个节点,配置数量可以很多、而且不固定。client要知道增加了什么配置,修改了什么,删除了什么配置,因此设定了watch。其中A复杂修改这些配置,N1,N2,...Nm这些节点监听通知,并更新软件引擎的变量,使其生效配置。

首先A在/group/policy下做create、delete、update操作后,都要set 一次 /group/policy节点。这会导致/group/policy的dataversion加1。并且可以知道有几次操作,dataversion就增加几。

伪代码如下:

doSomeOperion();

setData("/group/policy","")

Ni节点要对/group/policy下节点发生修改的事件进行watch,还要对/group/policy节点自身的修改进行watch。因此如果Ni没有错过通知的话,它将一次触发两个通知:1)配置变化通知;2)/group/policy数据更新通知。

Ni要在本地保存三个变量current_dataversion,current_zxid

在Ni client初始化时:

current_dataversion=/group/policy的dataversion;

current_zxid=/group/policy的mzxid;

然后在watch到配置发生变化的回调函数中:

doSometing(); //生效具体配置

current_dataversion += 1; //期待/group/policy的下一个dataversion增加1

在watch到/group/policy的数据发生变化后回调函数中:

if current_dataversion == /group/policy的dataversion: //意味着没有漏掉消息

current_zxid = /group/policy的mzxid

elif next_dataversion < /group/policy的dataversion: //一位置有配置变化的消息没有收到

遍历/group/policy子节点

if /group/policy/znodei的mzxid > current_zxid:

使用znodei中的配置。

删除已经不存在znode的配置项;

同步完成;

next_dataversion = /group/policy的dataversion

current_zxid = /group/policy的mzxid

这样就可以保证client能够发现自己错过了消息,并发现哪些znode的修改被自己错过了。那么至少在下一次发生修改配置后,client能够完全与当前配置一致。

我们可以写一个场景验证下:

初始时/group/policy下为空,/group/policy的stat为(mzxid=2,dataversion=0)

    current_dataversion=0;
    current_zxid=2
 1)create /group/policy/n1(mzxid=3,dataversion=0) 收到通知 current_dataversion+=1 (等于1)
 2)set /group/policy (mzxid=4,dataversion=1) 收到通知 curren_dataversion==/group/policy.dataversion,没有漏掉通知
                                                      current_zxid=/group/policy.mzxid (等于4)
 情形一)                                                     
 3.1) create /group/policy/n2 (mzxid=5,dataversion=0) 没有收到通知 current_dataversion不变(等于1)
 4.1)set /group/policy (mzxid=6,dataversion=2) 收到通知 current_data < /group/policy.dataversion,得知漏掉了通知,并且知道漏掉1个
                                                         同步mzxid大于current_zxid(值为4)的节点(即n2节点)配置;
                                                         删除已经不存在znode的配置;
                                                         current_data = /group/policy.dataversion (等于2)
                                                         current_zxid = /group/policy.zxid (等于5)
  情形二)
  3.2)create /group/policy/n2(mzxid=5,dataversion=0) 收到通知 current_dataversion+=1 (等于2)
  4.2)set /group/policy (mzxid=6,dataversion=2)  没有收到通知  current_zxid(=4)不变。漏掉该消息是没有关系的,再次收到该消息时,会更新current_zxid
  情形三)
  3.3)create /group/policy/n2(mzxid=5,dataversion=0) 没收到通知 current_dataversion不变(等于1)
   4.3)set /group/policy (mzxid=6,dataversion=2)  没有收到通知   current_zxid(=4)不变。
   5)create /group/policy/n3(mzxid=7,dataversion=0) 收到通知 current_dataversion+=1 (等于2)
   6)set /group/policy (mzxid=8,dataversion=3)   收到通知    current_data < /group/policy.dataversion 得知漏掉了通知
                                                              同步mzxid大于current_zxid(值为4)的节点(即n2,n3节点)配置;
                                                              删除已经不存在znode的配置;
                                                              current_data = /group/policy.dataversion (等于3)
                                                              current_zxid = /group/policy.zxid (等于8)

通过这种方式,可以让client端知道自己错过了通知,至少在下次收到/group/policy节点更新通知时,能够重新同步配置。因此可以保证client之间迟早会变得同步。

更进一步,可以额外再增加时钟来触发对/group/policy节点的检查。这样就可以保证一个时钟间隔之后,client肯定是同步的。

时间: 2024-10-09 00:56:03

确保zookeeper一定收到通知消息的方法的相关文章

Objective-C(十九、通知-消息发送模式之一)——iOS开发基础

结合之前的学习笔记以及参考<Objective-C编程全解(第三版)>,对Objective-C知识点进行梳理总结.知识点一直在变,只是作为参考,以苹果官方文档为准~ 十九.通知-消息发送模式之一 1.几个基本概念 (1)通知:在面向对象的程序中,有时需要将发生的时间通知给多个对象的消息发送模式: (2)通知中心:期望取得通知的对象预先向通知中心注册期望取得的通知: (3)发送:某对象向通知中心发送消息发送请求,只有注册过该通知单额对象,都可获得通知中心推送的消息: (4)观察者:消息发送目标

微信公众平台群发消息的方法及注意事项

群发消息的方法 操作方法:登录微信公众平台(https://mp.weixin.qq.com)=>群发消息=>根据需要填写文字/语音/图片/视频/录音等内容后,选择对群发对象.性别.群发地区发送即可. 群发消息内容 目前支持群发的内容:文字.语音.图片.视频.图文消息. 1.群发内容中需添加文字+图片+视频,可先在“素材管理”中设置图文消息,然后群发时选择“图文消息”类型即可. 2.上传至素材管理中的图片.语音可多次群发,没有有效期. 3.群发图文消息的标题上限为64个字节: 4.群发内容字数

swift中通知的使用方法

其实swift语言和OC语言,在本质上都是一样,其里面的方法之类的也基本相同.通知的使用方法也是一样,只是代码的书写格式发生了改变而已.下面我通过一个简单的小需求,也讲一讲通知,用swift中的闭包,也能完成此功能. 使用通知需要注意事项: 1,先确保接收中心存在,在设置通知中心. 2,最后一定要移除通知中心. 3,通知也是可以传值的,放在userInfo里面. 具体界面效果,我在这里就不截图了,希望各位开发者,自己写一遍,然后运行. ViewController // //  ViewCont

Sys.WebForms.PageRequestManagerParserErrorException:无法分析从服务器收到的消息

我引起此原因的功能如下: 在aspx页面添加按钮 JS方法: function downPPT() { $("#Btn_DownPPT").click();    } <body>    <form id="form1" runat="server">    <asp:ScriptManager ID="ScriptManager1" runat="server">   

未能分析从服务器收到的消息,.cs文件里面用response.write输出js弹框出错,用了局部跟新

转载:https://www.cnblogs.com/shenyixin/archive/2012/03/08/2385376.html 中文: Sys.WebForms.PageRequestManagerParserErrorException: 无法分析从服务器收到的消息,之所以出现此错误,常见的原因是:通过调用Response.Write()修改相应时,将启用响应筛选器.HttpModules或服务器追踪. 详细信息:分析附近的"输出内容"时出错. 解决方法如下: 1.如果调用

[技术博客]react native事件监听、与原生通信——实现对通知消息的响应

在react native中会涉及到很多页面之间的参数传递问题.静态的参数传递通常利用组件的Props属性,在初始化组件时即可从父组件中将参数传递到子组件中.对于非父子关系的组件来说,无法直接传递参数,此时可能会用到react-navigation来传递:此外,若要将异步函数.不可预料的事件执行等得到的参数用于页面刷新时,前述的方法都不太奏效. DeviceEventEmitter react-native中采用了DeviceEventEmitter来实现对事件的监听,实现非父子关系的页面之间的

微信公众号通知消息

微信公众号可以将消息交给WeixinHandler处理,如果能主动发送通知消息到手机微信就非常方便了,微信公众号的"发送模板消息"接口可以使用. 关注我的测试号,获取openid值关注时会通知openid值,手动发送"openid"也可获取openid值 调用微信通知消息接口参数为openid.text或chat.text用于指定通知消息,chat用于聊天响应消息(与发chat内容到测试号的效果一样) 使用场景: 服务器监控使用crontab定时执行监控脚本,如果指

另类保存微信公众平台历史消息的方法 - 星标消息

前面怎样把微信聊天记录导出备份到电脑[微信公众平台技巧]介绍的通过复制源代码来保存微信公众平台历史消息的方法,有网友反映说不会用批量替换.不会批量换行保存,一头雾水.这里我们就说个简单的方法,直接用星标消息保存,打开微信公众号消息管理,鼠标移动到你要保存的消息,右侧会显示几个菜单,其中有个星星形状的,默认是灰色的,如下图红框所示,点击后变成黄色的小星星,这样微信公众号星标信息就完成了,so easy!哪里要存点哪里! 腾讯客服提供的回答"微信公众号星标信息有什么用?" 他们的解释是:

建立空窗口时,窗口函数受到的消息(三种拦截记录消息的方法)

新窗体上放一个Button1和Panel1,仅仅Form1就会收到以下消息: procedure TWinControl.DefaultHandler(var Message); begin if FHandle <> 0 then begin with TMessage(Message) do begin if (Msg = WM_CONTEXTMENU) and (Parent <> nil) then begin Result := Parent.Perform(Msg, W