哈 如我所愿,你们还是被标题吸引进来了。论标题的重要性
今天有个线上小bug,是由zookeeper初始化引起的,把查找修复过程记录一下,其实和zookeeper没多大关系,还是并发的事情,不感兴趣的兄弟们可以撤了,O(∩_∩)O
我的程序中,连接了zk,来做一些分布式通知和逻辑控制的事情,用了别人封装的客户端,来注册、监听、获取通知、响应对应逻辑。
但是,spring启动加载时,报了个错,幸亏发现了
zookeeper is not initialized.... 什么鬼。。。
zk注册失败,就意味着依赖zk的控制逻辑都会时效,比如动态日志级别切换什么的,得找出原因呐。。。
首先找到了spring 配置文件中的zk客户端
可以看到,根据zk服务器地址,节点路径,在init方法中进行了初始化,(这里的同步逻辑设置成了false),而false的含义是要在init时,重新启动一个线程,去做初始化的工作(炸弹。。。)
接下来是注册节点和监听器的操作类。
这里,用配置的形式,将上面的zkClient添加到这个类的属性中,然后再在init方法中,对将会用到的监听器进行注册
这时候,问题就来了,当调用super的注册方法时,会用到此类中的属性zkClient,但是zkClient此时真的已经初始化好了么,不一定啊!
因为我们设置的sync 是false,只是将初始化的工作交出去了,完成没有,真心不知道啊,所以,一旦没有初始化完成,就使用它去进行注册,一定会抛出异常。
是不是很熟悉的错误,在前面的volatile文章中就提到过“类的安全发布”,很显然,这时候的zkClient类的发布,是不安全的
怎么解决呢,一个方法是把sync设置成true,同步模式,注册完再说别的。
第二个办法呢,就是弃用配置的形式注入zkClient,改成
注解形式,并设置成线程可见。