Skip to content

应用优雅上下线

一句话机制

优雅下线的本质是「先停进水、再放完水」:先摘监控、摘流量、停止接收新请求,再把已在途的请求处理完,最后释放资源退出。它靠层层递进的信号/钩子机制实现——从 OS 信号一路传导到 JVM、Spring、Dubbo。

「不优雅」的代价(反面清单)

  1. 停服务却没关监控 → 应用停了还疯狂报警。
  2. 停服务没通知调用方 → 大量调用失败。
  3. 线程执行到一半 JVM 进程被强杀 → 数据不一致。
  4. 服务还没准备好就对外提供 → 启动期大量失败调用。

分层的优雅停机机制

机制要点
OS信号kill -15(SIGTERM,可被处理,优雅)vs kill -9(SIGKILL,立即强杀,≈ 宕机)
Dockerstop/killdocker stop = SIGTERM;docker kill = SIGKILL
JVMshutdown hookRuntime.addShutdownHook(Thread),JVM 正常关闭时回调
Springbean 销毁 + 事件容器初始化时注册 shutdown hook;DisposableBean.destroy() + ApplicationListener<ContextClosedEvent>
Dubbo优雅停机Provider 先标记不再接收新请求(新请求报错让 Client 重试)、等在途线程执行完、超时强关;Consumer 不发新调用、等未响应请求返回

不变量

  1. SIGTERM 可被处理、SIGKILL 不可被处理。想优雅停机,必须给进程发 SIGTERM(kill -15 / docker stop)而非 SIGKILL。
  2. 上层机制都建立在下层之上:Spring/Dubbo 的优雅停机底层都是 JVM shutdown hook,而 shutdown hook 只在「正常关闭」时触发——若被 kill -9 强杀,一切钩子都来不及执行。
  3. 优雅下线的正确顺序:摘流量(摘监控、摘 Service/注册中心)→ 处理在途请求 → 释放资源 → 退出。

常见误解

  • ❌ 「kill -9 快,用它关闭更省事」——错。SIGKILL 无法被捕获,等于模拟宕机,会丢失在途请求、跳过所有清理。
  • ❌ 「docker stop 是强杀」——错。docker stop 发的是 SIGTERM,给进程优雅关闭的窗口,超时(默认 10s)才会 SIGKILL。
  • ❌ 「优雅下线 = 进程正常退出就够了」——错。不摘监控、不摘流量、不等在途请求,进程「正常退出」照样产生报警和失败调用。

关联

  • 上游:优雅上下线
  • 同域:Docker技术栈总览 · [Kubernetes Pod与探针机制](./Kubernetes Pod与探针机制)(K8s 删除 Pod 同样走「preStop hook → SIGTERM → 宽限期 → SIGKILL」)
  • 域地图:运维与云原生
最近更新