优先用systemd,restart=on-failure最安全,只在非零退出、信号终止或oom时重启;需配restartsec=5、startlimitintervalsec=60和startlimitburst=3防雪崩,并用健康检查或watchdog应对“假死”。

用 systemd 或 supervisor 实现自动拉起是可行的,但选错方案或配错参数会导致“反复崩溃→重启→再崩溃”的死循环,掩盖真实问题。优先用 systemd,除非你明确需要 supervisor 的多进程组管理或非 root 环境适配。
systemd 服务文件里 Restart= 配什么才合理
Restart= 的取值直接影响是否误判正常退出为崩溃。设成 always 会连 exit(0) 都重启,极易引发循环;on-failure 是更安全的默认选择,它只在进程因信号终止(如 SIGSEGV)、被 OOM Killer 杀掉、或返回非 0 状态码时触发重启。
-
Restart=on-abnormal:跳过 exit code 0 和 signal 15(SIGTERM),适合有优雅关闭逻辑的服务 -
Restart=watchdog:必须配合服务内调用sd_notify("WATCHDOG=1"),适用于 Go/Python 框架内置 watchdog 的场景 - 务必搭配
RestartSec=5(避免密集重启)和StartLimitIntervalSec=60+StartLimitBurst=3(防启动风暴)
为什么进程“卡死”但 systemd 不重启
systemd 默认只检测进程是否退出,对高 CPU、死锁、HTTP 无响应等“假死”状态完全不感知。这不是配置错了,而是设计如此。
- 加
ExecStartPre=健康前置检查:比如ExecStartPre=/usr/bin/curl -f http://localhost:8080/health || exit 1,失败则拒绝启动 - 启用
WatchdogSec=30并要求服务主动上报,否则超时后 systemd 会发 SIGABRT 强制终止 - 设置资源限制:
MemoryMax=512M+OOMScoreAdjust=-500,降低被系统 OOM Killer 杀掉的概率
supervisor 配置 autorestart=unexpected 的实际效果
这个参数比 systemd 的 on-failure 更细粒度:它会忽略 exit code 0、15(SIGTERM)、143(SIGTERM 转换),只对意外退出(如段错误、未捕获异常、kill -9)触发重启。
- 必须配
startsecs=10:确保进程真就绪,不是刚 fork 出来就报 RUNNING - 配
stopwaitsecs=15:给应用留足时间清理连接、刷盘,避免强制 kill -9 留下脏状态 - 日志要分离:
stdout_logfile和stderr_logfile分开写,崩溃前最后几行 stderr 往往是关键线索
真正容易被忽略的是:无论用哪种机制,都得先确认崩溃原因本身——journalctl -u myapp.service -n 100 -f 或 supervisorctl tail myapp stderr 必须成为部署后第一眼要看的东西。自动重启只是兜底,不是替代调试。











