systemd 重启五次就不动了:start limit 把服务彻底停掉的三个细节
服务挂了,systemd 帮你重启了五次,然后彻底安静下来。systemctl status 显示 failed,日志停在最后一条 Failed with result 'exit-code',再往后什么都没有。你 systemctl restart 一下,它起来两秒又死,接着又是死的——但这次连重启都没有了。
这就是 StartLimitBurst / StartLimitIntervalSec 这对默认值在起作用。systemd 的默认策略是:10 秒内最多允许启动 5 次,超出后单元进入 failed 状态并且不再自动重启,日志里留下一条 Start request repeated too quickly。这条日志很容易被漏掉,因为它出现在 Scheduled restart job 之后,看起来像是重启链路自己坏了。
我在本机(systemd 255)用一个必死的单元复现了一下:
# systemd-run --unit=limit-test --property=Restart=always \
# --property=RestartSec=0.2 /bin/false
4 秒后查状态:
Result=exit-code
NRestarts=5
ActiveState=failed
日志里第五次重启之后紧接着:
limit-test.service: Scheduled restart job, restart counter is at 5.
limit-test.service: Start request repeated too quickly.
limit-test.service: Failed with result 'exit-code'.
重启计数器停在 5,之后等了十几秒也没有第六条。自动恢复在这里就终止了,但你不会收到任何告警——单元就是 failed,安安静静。
细节一:卡在 start limit 之后,systemctl start 也会失败
这一点最坑。此时手动 systemctl start 的返回是:
Job for limit-test.service failed because the control process exited with error code.
或者干脆没有输出,退出码非 0,服务不启动、日志也不追加。原因是 rate limit 的门还关着,你被自己的限流挡住了。必须先清掉失败状态:
systemctl reset-failed myapp.service
systemctl start myapp.service
reset-failed 会清掉 restart counter 和 failed 标记。排障时如果只看到「重启没用」,先想到这一步,能省掉大量在代码里瞎找 bug 的时间。
细节二:RestartSec 太小才是常见元凶
限流窗口是「10 秒内 5 次」。如果进程是启动即退(配置错、端口被占、缺环境变量、依赖没起来),配上 RestartSec=1,五次启动两秒就用完了;配上 RestartSec=0.2,一秒内就打满。
反过来,如果 RestartSec=5,理论上一分钟能启动 12 次,但任意 10 秒窗口里最多 2 次——永远碰不到 5 次的阈值,限流形同虚设,服务会以每 5 秒一次的节奏无限重启,把日志和 CPU 慢慢拖干。
两种情况都不健康,正确的方向是退避而不是固定间隔:
[Unit]
StartLimitIntervalSec=300
StartLimitBurst=10
[Service]
Restart=on-failure
RestartSec=5
10 次 / 5 分钟意味着前 50 秒允许快速重试(扛过瞬时抖动),之后就必须真的死够久才会被判失败。再配一个 OnFailure= 单元去发通知,或者干脆用监控盯 systemctl show -p NRestarts:
systemctl show myapp.service -p NRestarts -p ActiveState
只要 NRestarts 在增长、ActiveState 还是 active,就是「在重启但没起来」的中间态,这时更该报警——比等它彻底 failed 有信息量得多。
细节三:StartLimitIntervalSec=0 不是「关掉限流」的优雅写法
StartLimitIntervalSec=0 确实关闭限流,让 systemd 无限重试。但它把「试探性重启」变成「每秒一次的死循环」:如果 RestartSec 也很小,进程会以毫秒级频率拉起、崩溃、拉起,journal 几秒钟就能写出几万行,磁盘和 CPU 都被吃满——本来只是想让它别放弃,结果把整机拖下水。真要关限流,RestartSec 必须同步调大。
附带一个配置位置的坑
这两个键历史上在 [Service] 段,从 systemd 230 起挪到了 [Unit]。写错位置的行为是静默失效,实测 systemd-analyze verify 会告诉你:
demo.service:9: Unknown key name 'StartLimitIntervalSec' in section 'Service', ignoring.
ignoring 三个字意味着你精心设计的 10 次 / 5 分钟根本不存在,实际跑的还是默认的 5 次 / 10 秒。改完配置务必跑一次 systemd-analyze verify,比看文档快。
检查清单
- 服务隔一会儿就死、日志没有新内容 → 先看有没有
Start request repeated too quickly - 卡在 start limit 后手动也起不来 →
systemctl reset-failed再 start - 启动即退的服务 →
RestartSec别小于 5,限流窗口放大到分钟级 - 只想让它一直重试 →
StartLimitIntervalSec=0必须配大RestartSec - 别让自动恢复在无告警的 failed 状态里终止 → 监控
NRestarts增长速度,或配OnFailure= - 这两个键写在
[Unit],改完跑systemd-analyze verify
- 点赞
- 收藏
- 关注作者
评论(0)