来解决Dubbo接口的重复登出问题。转载本文请联系捕虫大师公众号。背景本人在公司负责自主研发的dubbo注册中心相关工作。在群里经常收到业务方反馈dubbo接口注销错误。经过排查,确定是同一个接口两次调用了注销接口。由于我们的注册中心注销接口不能重复调用,所以第二次调用会报找不到实例的错误,因为实例已经注销了。虽然这个报错只是打印错误日志,不影响业务,但本着followthrough的精神,还是决定一探究竟,何况反复注销还会增加应用的结束时间,影响回滚速度发布。问题又出现了。我从业务端拿到了dubbo版本,是内部基于开源2.7.3定制的版本。该版本的修改主要涉及安全漏洞修复和部分业务适配。写了个demo跑了,然后kill了,发现报错了。.为了确定问题不是内部修改引起的,我用开源版本2.7.3再次测试,发现还是报错。同时,为了确认这是一个bug,我将dubbo版本修改为2.7.7进行测试,发现这个版本不再报错了。说明重复注销至少是开源dubbo2.7.3的bug,在2.7.7高版本已经修复。于是就有了解决办法:升级dubbo,不过这么简单的话就不会有这篇文章了。修改了dubbo内部。如果要升级,则必须将更改合并到新版本。就算升级了内部的dubbo版本,也不可能这么快的推动业务端的升级。所以,应该先找出BUG是哪里引起的,再看注册情况。中心的扩展是否可以修复这个问题,如果不能,只能在dubbo内部版本修复。排查疑似ShutdownHook由于这几天研究了ShutdownHook(点击查看原文跳转到?),立马怀疑可能是ShutdownHook有问题。Dubbo2.7.3代码中ShutdownHook的实现是在DubboShutdownHook类中,顺着代码整理出如下关系。可以看到dubbo本身和spring都注册了ShutdownHook,不知道这里是不是重复注册了ShutdownHook。于是调试看是否重复注册。这里有一点经验。IntelliIDEA在调试ShutdownHook的执行时,需要手动kill掉进程才能触发调试。在IDE中点击关闭按钮不会触发DubboShutdownHook.doDestroy中的断点。Debugfound只会执行一次,也就是说spring和dubbo的ShutdownHook只会被注册一次。这是如何实现的?经过多次测试,我发现了dubbo的一个非常强大的设计。DubboShutdownHook中有register和unregister方法,分别是注册和注销ShutdownHook。两种方法都设置了断点。当程序启动的时候,我们发现这样一个有趣的执行顺序:综上所述,dubbo本身注册了ShutdownHook,但是如果你使用到spring框架的时候,spring框架在初始化的时候取消了dubbo注册的ShutdownHook,这样只保留了spring的ShutdownHook,真的秒了!实现的代码只有几行publicstaticvoidaddApplicationContext(ApplicationContextcontext){CONTEXTS.add(context);if(contextinstanceofConfigurableApplicationContext){((ConfigurableApplicationContext).registerShutdownHook();DubboShutdownHook.getDubboShutdownHook().unregister();}BeanFactoryUtils.addApplicationListener(context,SHUTDOWN_HOOK_LISTENER);}所以怀疑的ShutdownHook问题被证明是没有问题的。必须很容易解决可以从注销堆栈稳定重现的问题。使用IDE的debug查看两次注销的调用栈,在注册中心扩展的unregister方法处加断点。您可以看到以下两个不同的来源。在堆栈信息代码中体现为一次ShutdownHook执行触发两次注销。接下来比较容易检查,一步步debug,这里说明AbstractRegistryFactory.destroyAll()是销毁所有的注册中心,销毁的时候会调查注册中心的注销接口。destroyProtocols就是销毁所有的协议。进入注册中心,然后调用注册中心的注销接口。那么dubbo2.7.7是如何避免这个问题的呢?在dubbo2.7.7的代码中,registry的protocol在销毁的时候得到的代码多了一点。中心被销毁后,被销毁的变量设置为true,所以注册协议再次获取注册中心时,原来的注册中心已经不可用了,拿到的是一个空的注册中心。调用logout自然是没有效果的。追溯到github,这次的PR是https://github.com/apache/dubbo/pull/5450。此修复程序已在2.7.5中修复。综上所述,2.7.0~2.7.4版本存在dubbo重复注销问题。2.7.5修复,zk注册中心不会报错,可能感觉不到,但确实存在,会减慢申请的关闭速度。通过跟踪发现这个问题可以在注册中心的扩展中解决,这样注册中心的销毁只能调用一次,再小的问题,有空再研究时间,你会收获一些新的知识,比如这次dubbo中ShutdownHook的巧妙设计
