linux systemd 服务优雅停止的关键是设 killmode=process 使仅主进程收 sigterm,并配 timeoutstopsec=20–45 秒让其协调子进程清理,避免默认 control-group 模式导致 worker 被误杀,且无需额外 execstop。

Linux 中配置 systemd 服务的优雅停止,核心是让主进程收到 SIGTERM 后自行协调子进程完成清理,而不是由 systemd 强制杀掉所有进程。关键不在“发什么信号”,而在于“向谁发”和“给多久时间”。
KillMode 设为 process
默认的 KillMode=control-group 会把 SIGTERM 同时发给 master 和所有 worker 进程,导致 worker 来不及处理完请求就被中断。改成 process 后,systemd 只向主进程(即启动命令直接 fork 的那个)发送信号,其余 worker 由主进程自主管理。
- Nginx、Redis、自研 QT 后台服务等主从架构程序都适用该模式
- 避免使用
mixed—— 它对 worker 发SIGQUIT,可能触发非预期退出 -
none基本不用,完全放弃 systemd 的终止控制
设置合理的 TimeoutStopSec
主进程需要时间完成优雅退出:关闭监听端口、等待 worker 处理完存量连接、释放锁或刷盘缓存。默认 90 秒太长,10–30 秒更贴近实际需求。
- 例如 Nginx 通常 20 秒足够:
TimeoutStopSec=20 - 若业务涉及长连接或批量落库,可设为 30 或 45
- 超时后 systemd 才 fallback 发
SIGKILL,不是立刻硬杀
不写 ExecStop,依赖程序原生响应
只要主进程能正确捕获 SIGTERM 并执行清理逻辑(绝大多数成熟服务都支持),就不需要额外定义 ExecStop=。手动写脚本反而容易绕过程序内置的优雅流程。
- 比如 Nginx master 收到
SIGTERM会自动进入 graceful shutdown 流程 - 强行加
ExecStop=/bin/kill -15 $MAINPID是多余操作 - 只有当程序完全不响应信号时,才需用脚本兜底(属异常情况)
修改并生效的实操步骤
推荐用 systemctl edit 覆盖式修改,不直接编辑原始 unit 文件:
- 运行
sudo systemctl edit nginx(或其他服务名) - 输入:
[Service]<br>KillMode=process<br>TimeoutStopSec=20
- 保存退出,执行
sudo systemctl daemon-reload - 验证:重启服务后,
systemctl stop nginx观察日志是否出现 “gracefully shutting down” 类提示











