Restart=on-failure是生产环境唯一合理的选择,因它仅在非零退出码、信号终止或启动超时时重启,不干扰手动stop,避免always导致运维失效,且需配合RestartSec和StartLimit*防雪崩。

必须显式配置 Restart=on-failure,否则崩溃后 systemd 默认静默退出,连段错误都不会管。
为什么 Restart=on-failure 是生产环境唯一合理的选择
systemd 默认 Restart=no,进程一退出就停着,不会尝试拉起。设成 Restart=always 更危险:你执行 systemctl stop mysqld 后,它会立刻被重新拉起,运维操作直接失效。
Restart=on-failure 只在以下情况触发重启:
- 进程以非零退出码退出(比如配置校验失败、初始化报错)
- 被信号终止(
SIGSEGV、SIGKILL、SIGTERM超时未响应等) - 启动超时(由
TimeoutStartSec控制)
它不响应 exit(0) 这类“正常退出”,避免干扰平滑关闭或 reload 流程。
RestartSec 和 StartLimit* 必须一起配,否则可能雪崩或彻底拒启
光有 Restart=on-failure 不够。若服务反复崩溃,systemd 会高频拉起进程,耗尽内存/CPU,甚至压垮整机——就像没刹车的车。
关键参数组合:
跨平台内容管理系统构建与修改工作流(WordPress、Shopify、Wix、Squarespace、Drupal、WooCommerce、Joomla、HubSpot CMS Hub、Web…)
-
RestartSec=5:每次失败后等 5 秒再试,留出端口释放、磁盘 IO 缓冲时间 -
StartLimitIntervalSec=60:滚动统计窗口为 60 秒 -
StartLimitBurst=3:该窗口内最多允许启动 3 次
超出后 systemd 标记为 start-limit-hit 并拒绝再试,此时必须人工查日志,而不是等它自己恢复。
验证当前生效值:systemctl show <service-name> | grep -E "(Restart|StartLimit)"</service-name>
容易被忽略但致命的三个坑
很多服务加了 Restart=on-failure 却没真正重启,主因是以下三点没处理:
-
没配
RestartPreventExitStatus=1:MySQL 启动时发现配置语法错误(退出码 1),默认也会触发重启,导致“启动→失败→重启→再失败”死循环 -
没 reload 配置文件:改完
.service文件后,必须执行sudo systemctl daemon-reload,否则systemctl show看到的仍是旧值 -
没确认主进程识别方式:Nginx、Gunicorn 等 fork 多进程的服务,systemd 若只监控前台命令,会误判 master 已退出。必须用
Type=notify或Type=forking+PIDFile=显式指定主进程
自动重启不等于故障修复,日志和状态必须人工确认
Restart=on-failure 只是把进程拉起来,掩盖不了底层问题。MySQL 崩溃后自动重启,InnoDB 可能处于不一致状态;Python 服务因数据库连接超时崩溃,重启后仍会重连失败。
每次触发重启后,务必检查:
-
sudo journalctl -u <service-name> -n 50 -e</service-name>,重点搜Address already in use、InnoDB initialization failed、Connection refused - 服务自身的健康接口(如
/health)是否真返回 200 - 依赖项(DB、Redis、网络)是否已就绪,避免用
After=network.target而应选After=network-online.target
最常被跳过的动作:重启后不看日志,只看 systemctl status 显示 active 就以为万事大吉——而真正的错误往往藏在第 3 行之后。
















