设为首页 收藏本站
查看: 911|回复: 0

[经验分享] 确保zookeeper一定收到通知消息的方法

[复制链接]

尚未签到

发表于 2019-1-8 12:52:01 | 显示全部楼层 |阅读模式
  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肯定是同步的。




运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-660785-1-1.html 上篇帖子: zookeeper以及kafka环境的搭建 下篇帖子: Centos7以普通用户启动zookeeper并加入开机自启动服务
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表