Spring Boot 服务挂了却没重启?先分清 systemd 的三次判断

线上有个 Spring Boot 服务退出后没有再起来,第一反应通常是补一句 Restart=always。我见过这么改的,结果是发版时正常停掉的进程也被拉回来了,现场更乱。

systemd 不是看到进程没了就无脑重启。它至少要过三道判断:这次退出算不算失败,重启次数有没有撞限额,当前追踪到的到底是不是你以为的那个主进程。

先看退出为什么没有被算成失败

对常驻服务,Restart=on-failure 通常是比 always 更稳的默认选择。systemd 的官方说明也把它列为长运行服务的推荐项。

但它只会在这些情况重启:

  • 进程返回非零退出码
  • 进程异常被信号终止
  • 服务启动或运行超时

退出码是 0,或者是有意停止的 SIGTERMSIGINT,都不属于它要补救的故障。

所以排查时别只盯着「进程没了」。有些启动脚本把 Java 异常吃掉以后又 exit 0,systemd 会认为这次服务正常结束。手动执行 systemctl stop 后不自动拉起也完全正常。

先看这一组信息:

bash 复制代码
systemctl status demo-api
systemctl show demo-api -p Result -p ExecMainCode -p ExecMainStatus -p NRestarts
journalctl -u demo-api -b --no-pager -n 100

我一般先找两件事:最后一次退出的 code 和 status 是什么,日志里失败发生在 Java 进程里还是发生在启动命令本身。

重启策略生效了,也可能被限频拦住

服务连续崩溃时,systemd 会遵守 RestartSec= 的等待时间,但不会无限次地拉起。它还会按 StartLimitIntervalSec=StartLimitBurst= 做启动限频。

看到 start-limit-hit,不要急着把阈值调大。那只是在让错误更快刷屏。先把导致崩溃的配置、依赖或端口问题修掉,之后再清理失败状态:

bash 复制代码
sudo systemctl reset-failed demo-api
sudo systemctl restart demo-api

下面这份 unit 文件适合先把行为讲清,不是照抄到所有机器上的万能模板:

ini 复制代码
[Unit]
Description=demo-api
StartLimitIntervalSec=60
StartLimitBurst=3

[Service]
User=app
WorkingDirectory=/srv/demo-api
Type=exec
ExecStart=/usr/bin/java -jar /srv/demo-api/app.jar
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

这里的 60 秒和 3 次只是一个明确的保护边界。实际值要看服务启动成本、依赖恢复速度和报警承受能力。把 RestartSec=0 当成「恢复更快」往往不是好事,它会让崩溃循环更快撞上限频。

Type=exec 解决的不是应用启动失败

很多 unit 文件完全不写 Type=,默认是 simple。对于长期运行的 Java 进程,Type=exec 有个很实在的好处:可执行文件不存在、用户不存在这类 execve 之前的启动错误,systemd 能更可靠地记录为启动失败。

但别把它神化。JAR 已经被 Java 拉起来,应用随后因为数据库连不上而退出,这仍然要靠退出状态和日志来判断。它不会替 Spring Boot 判断「业务已就绪」。

面试里怎么收这题

被问「为什么不用 Restart=always」,我会先说清目标:守住异常退出,不干预运维的正常停止。

然后补一句,真正可靠的配置不只是一个 Restart。要同时确认退出状态能反映失败,给重启留出间隔,再让限频把持续崩溃挡住。这样面试官继续问服务为什么没拉起,才有具体的排查顺序,不会只剩一句「加个重启策略」。

资料核对:systemd.service(5)、systemd.unit(5)、Spring Boot Reference Documentation 的 Linux systemd service 示例。

相关推荐
旺仔学长 哈哈2 小时前
52486|高校专业评估不再靠表格:Spring Boot 本科专业质量评估管理系统实战
数据库·spring boot·毕业设计·教育管理
weixin_BYSJ19872 小时前
springboot小区物业管理小程序---附源码45555
java·javascript·spring boot·python·django·flask·php
RuoyiOffice3 小时前
抓包还能看到密码?Vue3 + Spring Boot 3 接口 AES/RSA 加解密(@ApiEncrypt)全链路实战
spring boot·vue3·aes·rsa·接口安全·spring boot 3·apiencrypt
凤山老林3 小时前
零停机数据库演进:Spring Boot 集成 Flyway 与平滑DDL变更策略
数据库·spring boot·后端
抓哇小菜鸡3 小时前
Spring Boot + 本地大模型(Ollama/DeepSeek) + MyBatis-Plus 企业级智能体数据分析系统从零到一源码全解析
spring boot·后端·mybatis
趴下吧3 小时前
spring boot启动流程总结
java·spring boot·spring
码农进化录3 小时前
Java 程序员的 AI 进化论 | AI 帮我做 MySQL 表结构升级,三天活变半天
java·spring boot·openai
JacksonMx4 小时前
ContentCachingRequestWrapper 实战:解决请求体“只能读一次”的官方方案
java·spring boot·spring
A黄俊辉A6 小时前
java RedisTemplate 的使用
java·spring boot·spring