您现在的位置是:亿华云 > IT科技
排查Dubbo接口重复注销问题,我发现了一个巧妙的设计
亿华云2025-10-09 03:29:40【IT科技】3人已围观
简介本文转载自微信公众号「捉虫大师」,作者捉虫大师。转载本文请联系捉虫大师公众号。背景我在公司内负责自研的dubbo注册中心相关工作,群里经常接到业务方反馈dubbo接口注销报错。经排查,确定是同一个接口
本文转载自微信公众号「捉虫大师」,排查作者捉虫大师。接计转载本文请联系捉虫大师公众号。口重
背景
我在公司内负责自研的复注dubbo注册中心相关工作,群里经常接到业务方反馈dubbo接口注销报错。销问现经排查,巧妙确定是排查同一个接口调用了两次注销接口导致,由于我们的接计注册中心注销接口不能重复调用,调用第二次会因为实例已经注销而报实例找不到的口重错误。
虽然这个报错仅会打印一条错误日志,复注不影响业务,销问现但本着 follow through的巧妙精神,我决定还是排查一探究竟,更何况重复注销也增加了应用的接计结束时间,影响了发布回滚速度。口重
问题复现
拿到业务方的dubbo版本,基于开源2.7.3内部定制的一个版本,该版本修改主要涉及安全漏洞修复以及一些业务适配,写了个demo跑起来,然后kill,发现果然报错了。
为了确定不是内部修改导致的问题,用开源的服务器租用2.7.3版本再次测试,发现还是报错。
同时为了确定这是一个bug,我将dubbo版本修改为2.7.7做测试,发现该版本不再报错。
说明了重复注销至少是开源dubbo 2.7.3的一个bug,在更高的2.7.7版本中已经被修复。
于是有了解决方案:升级dubbo,但如果这么简单就没有这篇文章了。
内部的dubbo已经做了修改,想升级得把改动merge到新版本,比较费劲
就算升级了内部的dubbo版本,也不可能这么快速推动业务方升级
所以应该首先找到bug是哪里导致的,其次看注册中心的扩展是否可以修复这个问题,如果不能修复,就只能在内部的dubbo版本中修复该问题。
问题排查
怀疑ShutdownHook
由于这几天研究过ShutdownHook(点击查看原文跳转《ShutdownHook原理》),第一时间怀疑ShutdownHook可能有问题。
dubbo 2.7.3代码有关ShutdownHook的实现在DubboShutdownHook类,免费信息发布网顺着代码梳理出如下关系
看到dubbo本身和spring都注册了ShutdownHook,更加怀疑这里是不是ShutdownHook注册重复了。于是debug看看是否是注册重复了,这里给一个小经验,IntelliIDEA调试ShutdownHook执行时,要手动kill进程才会触发debug,点IDE上的关闭按钮不会触发
在DubboShutdownHook.doDestroy打上断点,debug发现只会执行一次,这说明spring和dubbo的ShutdownHook只会注册一次,这是怎么实现的呢?经过很多次测试,发现了dubbo一个很牛逼的设计。
DubboShutdownHook中有register和unregister方法,分别是注册和注销ShutdownHook,在这两个方法上都打上断点,在程序启动时发现这样一个有趣的执行顺序:
总结一下是dubbo本身注册了ShutdownHook,但如果用到了spring框架,spring框架在初始化时注销了dubbo注册的ShutdownHook,这样就只保留了spring的ShutdownHook,云服务器提供商真是秒啊!实现的代码只有这短短几行
public static void addApplicationContext(ApplicationContext context) { CONTEXTS.add(context); if (context instanceof ConfigurableApplicationContext) { ((ConfigurableApplicationContext) context).registerShutdownHook(); DubboShutdownHook.getDubboShutdownHook().unregister(); } BeanFactoryUtils.addApplicationListener(context, SHUTDOWN_HOOK_LISTENER); }于是怀疑的ShutdownHook问题被证明没有任何问题了。
从注销堆栈继续排查
能稳定复现的问题一定很好排查,借助IDE的debug来看两次注销的调用堆栈,在注册中心扩展的unregister方法处加断点,可以看到如下两次来源不同的堆栈信息
代码中体现是
也就是说一次ShutdownHook执行,触发了两次注销。
接下来就比较好排查了,一步一步debug,这里解释下
AbstractRegistryFactory.destroyAll()是销毁所有注册中心,销毁时会调研注册中心的注销接口 destroyProtocols是销毁所有的protocol,注册中心的protocol在销毁时拿到registry,然后调用了registry的注销接口那么dubbo 2.7.7是如何避免这个问题的呢?
在dubbo 2.7.7的代码中,注册中心的protocol在销毁时获取注册中心稍微增加了点代码
原来在注册中心被销毁后,destroyed变量被置为true,从而在registry protocol再次获取注册中心时,已经拿不到了原先的注册中心了,拿到的是一个空的注册中心,调用注销,自然没有什么效果。
追溯了下github,这次PR是
https://github.com/apache/dubbo/pull/5450
这个修复在2.7.5就已经修复了
总结
dubbo重复注销问题存在于2.7.0 ~ 2.7.4版本,2.7.5修复,zk注册中心不会报错,可能无法感知,但它确实存在,也会拖慢应用的关闭速度 通过追查发现,其实该问题可以在注册中心的扩展中解决,让registry的destroy只能被调用一次 遇到无论多小的问题,有空都去钻研下,你会收货一些新知识,比如这次dubbo中ShutdownHook如此巧妙的设计很赞哦!(26)
相关文章
- 4、club娱乐
- 超级干货:3个性能监控和优化命令详解
- 华为海思总裁:备胎芯片“全转正” 要科技自立
- 13个Spring Boot 优质开源项目!超53K星,一网打尽!
- 为什么说注册域名注意细节?哪些我们不能忽视?
- 【LeetCode】均等概率问题,我有妙招!
- AnnotationAwareAspectJAutoProxyCreator类是干嘛的?
- Node.js中的异步Generator函数和Websockets
- 域名资源有限,好域名更是有限,但机会随时都有,这取决于我们能否抓住机会。一般观点认为,国内域名注册太深,建议优先考虑外国注册人。外国注册人相对诚实,但价格差别很大,从几美元到几十美元不等。域名投资者应抓住机遇,尽早注册国外域名。
- 测试同学上手Spring 之DI深入解析
热门文章
站长推荐
互联网其实拼的也是人脉,域名投资也是一个时效性很强的东西,一个不起眼的消息就会引起整个域名投资市场的动荡,因此拓宽自己的人脉圈,完善自己的信息获取渠道,让自己能够掌握更为多样化的信息,这样才更有助于自己的域名投资。
Nature撤稿!三年前微软在量子计算上的巨大胜利终究是错误
苹果警告中国开发者:不要绕过APP反追踪功能
Facebook 集群调度管理系统 · OSDI 2020
a、变更前的公司证件扫描件(代码证或者营业执照)及联系人身份证复印件、变更后的公司证件扫描件(代码证或者营业执照)及新的联系人身份证复印件;身份证复印件需本人签名,公司证件复印件需加盖公章。
关于机器学习实战,那些教科书里学不到的12个“民间智慧”
最新版Swagger 3升级指南和新功能体验!
一个没有 if 的Spring++框架就是这么肝