Skip to content
发布于 更新于

1. 背景 ​

一个系统会有许多的中间件组成,包括 RPC(Consumer&Producer),Http,Job,MQ(Consumer&Producer),当CI/CD流水线运行,实例机器被 下线时,如果Dubbo Consumer组件的线程组先被回收后,还可以继续不停消费业务消息,消费消息时会使用Dubbo Consumer组件去调用其他服务,此时 Dubbo Consumer的线程组已经被回收了,就会导致数据消费时异常。如果没有消费重试的机制,可以当这些下线时的消息丢失了。

2. 方案 ​

首先收到kill -9 或是 kill -15 的信号后,

  • 切断数据源头: Http, Dubbo, MQ consumer
  • 不再提交新的任务 Job ThreadPool
  • 等待 其他组件(Mq Sender,Rest Client,Dubbo Consumer,Transaction )的线程执行完成

3. API ​

shell
# 可以添加Jvm自带的钩子方法
Runtime.addShutdownHook()

# 对于Spring容器的应用,可以监听close event 事件来,进行组件的优雅下线。

4. 参考文献 ​

4.1. 为什么难做 ​

优雅上下线难点不在“收到退出信号”,而在于退出时应用内部有很多异步组件还在工作:

  • HTTP 请求还在处理
  • MQ 还在消费
  • RPC 客户端还在调用下游
  • 线程池里还有排队任务

如果处理顺序不对,就很容易造成消息丢失、半处理状态或下游调用失败。

4.2. 推荐顺序 ​

一个更稳妥的顺序通常是:

  1. 先摘流量入口。
  2. 停止继续接收新消息和新任务。
  3. 等待存量任务处理完成。
  4. 最后再释放线程池、连接池和中间件客户端。

4.3. 实现关注点 ​

  • 退出等待时间要有上限,不能无限阻塞。
  • MQ 消费位点提交和业务处理完成要配套设计。
  • 定时任务、异步线程池和 RPC 客户端要统一纳入生命周期管理。

基于 VitePress + GitHub Actions 自动部署