- Dubbo version: 3.1.0
- Java version: 1.8.0
- 在 Spring Boot 环境下启动 Dubbo Provider 应用
- 启动 Dubbo Consumer 并发持续调用 Provider 应用
- kill 该进程
像文档说的那样可以优雅停机
实际情况是会报一大堆异常,并将异常返回至 Consumer 端。异常内容大多是:
[ERROR][2022-09-18 15:52:05.826][tri-protocol-20881-thread-200][org.apache.dubbo.rpc.filter.ExceptionFilter] [DUBBO] Got unchecked and undeclared exception which called by 172.17.0.221. service: cn.jojo.api.service.bs.ms.IMediaService, method: getEditMediaResult, exception: java.lang.IllegalStateException: ExtensionDirector is destroyed, dubbo version: 3.1.0, current host: 172.17.0.28
问题根因
Dubbo 的优雅停机实际上有两种机制:
- Spring Boot 环境下
DubboDeployApplicationListener#onContextClosedEvent
监听到ContextClosedEvent
时执行停机。 - DubboShutdownHook 监听 JVM 的 shutdownHook
这两种机制同时运行时,会导致相互冲突,上边提到的报错ExtensionDirector is destroyed
就是因为 DubboShutdownHook 关闭了 ExtensionDirector
导致的。
在经过反复测试后,只保留 DubboDeployApplicationListener
事件监听机制,是可以实现优雅停机的,而 DubboShutdownHook
的停机实际上并不优雅,它只是停机而已,甚至用不到 dubbo.service.shutdown.wait
参数,这个参数是通过 DubboDeployApplicationListener
监听事件最后走到 RegistryProtocol
中实现的。
建议在 Spring Boot 环境下默认关闭注册 DubboShutdownHook
。
DubboShutdownHook
提供了参数 dubbo.shutdownHook.listenIgnore
来阻止注册 JVM shutdownHook,但是这个参数是在类构造器中初始化的,而这个类的构造器又调用太早,导致读不到配置中心的配置,连 Spring Boot 配置也读不到,只有添加启动参数 -Ddubbo.shutdownHook.listenIgnore=true
才行。
而添加启动参数在规模稍大一些的系统中,是很难做到的,大家都是用配置中心来统一管理配置。