优雅关机解决思路

本文分析了传统Spring和SpringBoot应用在关闭时遇到的问题,如MQ消费者和Dubbo线程在应用关闭时仍在运行导致异常。通过理解各组件依赖关系,提出了解决方案:确保MQ-Consumer和Dubbo服务的关闭顺序,以及在合适位置插入自定义关闭逻辑,实现优雅停机。
摘要由CSDN通过智能技术生成

背景

前段时间,线上X项目关闭时频繁抛出org.springframework.beans.factory.BeanCreationNotAllowedException。收集报错日志,大概分为以下两类:

  1. 由dubbo调用触发
    在这里插入图片描述

  2. 由MQ消费者触发
    在这里插入图片描述

原因

简单观察以上栈信息,结合异常触发的情景,我们可以确认的事实有以下几点:

  • 应用正在关闭
  • MQ消费者在消费消息
  • Dubbo线程在处理请求
  • Spring容器的Bean正在销毁,不允许创建新的实例

不合理之处很明显,应用关闭时MQ消费者不应该再消费消息,Dubbo也不应该在接收请求。异常抛出的直接原因是MQ消费者和Dubbo线程依赖的Bean被销毁了,根本原因是停机顺序混乱。

分析

按照运行方式,我们的Spring应用大致可以分为两类:

  • 独立的Tomcat运行Spring应用——传统Spring应用

  • Spring内嵌Tomcat以jar包的形式运行,也就是SpringBoot

现在我们以Spring容器、Servlet、Dubbo、MQ-Consumer做组件为例,简单分析一下以上两类情况如何做到优雅停机。

传统Spring应用

我们首先分析Spring容器、Servlet、Dubbo、MQ-Consumer这四者的依赖关系
在这里插入图片描述

如上图所示,MQ消费者工作时需要依赖Dubbo服务和Spring容器;Servlet提供Http服务时需要依赖Dubbo服务和Spring容器;Dubbo服务需要依赖Spring容器。本着被依赖者要先于依赖者启动,后于依赖者关闭的原则,各组件的关闭顺序应该为:MQ-Consumer|Servlet(不分先后)、Dubbo、Spring容器。然而,实际上的关闭顺序却并不是这样。

以X项目为例,其生命周期的控制由Servlet容器占主导地位。
在这里插入图片描述

应用启动时,

  1. 首先执行Servlet容器初始化,触发org.springframework.web.context.ContextLoaderListener#contextInitialized方法,初始化并刷新RootApplicationContextServiceBean和DAOBean等实例化并初始化,MQ-Consumer和Dubbo服务也是在此时启动的;
  2. 初始化org.springframework.web.servlet.DispatcherServlet等Servlet和Filter,触发WebApplicationContext初始化,并设置和RootApplicationContext的父子关系,然后刷新容器,ControllerBean就是在此时实例化的。至此,Servlet容器启动完毕,可以对外提供http服务了。

应用关闭时,进程收到SIGTERM信号,有两个重要的钩子会被触发,一个是org.apache.catalina.startup.Catalina.CatalinaShutdownHook,另一个是org.apache.dubbo.config.DubboShutdownHook

其中DubboShutdownHook执行时会关闭Dubbo服务。而CatalinaShutdownHook执行过程中会顺序触发以下内容:

  1. 销毁Servlet和Filter。
  2. 销毁DispatcherServlet时会触发WebApplicationContext关闭,Controller等Bean会被销毁。
  3. 调用javax.servlet.ServletContextListener#contextDestroyed方法。
  4. org.springframework.web.context.ContextLoaderListener#contextDestroyed被调用时会关闭RootApplicationContextServiceBean和DAOBean会在此时销毁,MQ-Consumer也是在此时作为一个普通的Bean被关闭的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值