`
carver
  • 浏览: 49212 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

ZooKeeper全局锁WriteLock选举的BUG

    博客分类:
  • Java
阅读更多

最近项目中采用ZK去选择分布式集群的Master/Slave,生产环境运行一段时间中,经常出现同时存在多个Master的问题,然后去阅读了一下ZK扩展包的源码,发现两个BUG:

 

BUG:多机器同时获取WriteLock全局锁时有可能会有多个机器成为Leader。

原因分析:WriteLock创建临时自增节点是采用x-session_id-sequece_no的方式,在选举Leader时,通过TreeSet对节点进行排序,最小的节点就会被选为Leader,其它的会被选为Follower。由于ZNodeName的compareTo方法的实现问题,WriteLock获取的锁时并不是按sequence_no最小的来选择,而是先根据session_id的字符串进行比较,再比较sequence_no,如果WriteLock后创建的节点的session_id比前面的小(可能性比较大),这种比较方式就有可能导致产生多个Leader。如:

机器1创建了:x-231622919316419832-0000000183

机器2创建了:x-231622919316419833-0000000184

机器3创建了:x-87556941509467773-0000000185

机器4创建了:x-159565318739768636-0000000186

由于机器1最先启动,只有一个节点生成,所以理所当然成为Leader,但由于ZNodeName的compareTo方法的问题,机器4启动后发现session_id值比当前Leader的值要小,所以机器4也被认为是Leader,这样就同时存在了两个Leader。

另外,不仅在机器启动和重启的时候发生,ZK会话超时重连,而会出现此情况。

如何改造:

去除ZNodeName的compareTo方法对session_id的比较,仅保留对sequece_no的比较。

 

0
0
分享到:
评论
4 楼 comedsh 2016-11-15  
这个问题其实是需要在你的代码(选主的代码)中去控制的;任何时候,选主只能出现一个,如果当选主成功之后,后续有符合标准的节点,必须等待“主节点”(之前选主成功的节点)退出,挂掉,或者主动退出以后,才能成为下一个主节点。所以,这个本身不是 WriteLock 的问题。另外 WriteLock 之所以使用 session_id 作为 lock 的名称,是有非常重要的考虑的,是为了实现在分布式环境下的“幂等性”~,所以建议不要轻易去改变它的内部实现逻辑。
3 楼 weiboxie 2014-04-17  
session_id 应该是一直增加的,所以后启动的机器4 的session_id 不可能小于之前leader 的 session_id
2 楼 carver 2012-06-28  
这个不是ZK正式发行包里面的,是扩展包,官方没有修复,我自己改了一下代码。
1 楼 roki 2012-06-28  
哪个版本上的bug啊? 新版修复了吗?

相关推荐

Global site tag (gtag.js) - Google Analytics