systemctl start myapp 执行完没有任何输出,curl 还是连不上;或者 systemctl status 明明写着 active (running),端口却不通。
systemctl 的坑基本集中在两件事上:状态字面含义和unit 文件到底在哪一层生效。下面这 5 个状态按排障顺序排列,从「文件认没认到」一直查到「改完为什么不生效」。
说明:本文示例输出取自 systemd 的常见行为,具体路径、PID、退出码以你的环境为准;命令本身可以直接复制执行。
状态一:Loaded 行——unit 文件到底从哪来
Loaded: loaded (/etc/systemd/system/myapp.service; enabled; vendor preset: enabled)
这一行告诉你文件路径、是否开机自启。三种异常写法:
Loaded: not-found:unit 文件不存在。要么服务名拼错,要么文件放错了目录。先确认名字:
systemctl list-unit-files | grep myapp
Loaded: masked:服务被 mask 了,start会直接报Unit myapp.service is masked.。解除:
sudo systemctl unmask myapp
Loaded: bad; vendor preset::unit 文件语法有问题。让 systemd 自己指出问题:
systemd-analyze verify myapp.service
状态二:active (running) 不等于服务可用
status 里的 Active 行有四种常见值:
active (running):进程在跑。但进程在跑不代表端口通了、不代表业务正常active (exited):oneshot 类型的服务执行完正常退出。这是成功,不是故障inactive (dead):没在运行。可能手动停的,也可能启动失败后自己退了failed:上次启动失败
看到 active (running) 但访问不通,往两个方向查:
ss -lntp | grep 8080
journalctl -u myapp -n 50 --no-pager
高频原因:服务只绑了 127.0.0.1,外部访问不到;端口被别的进程占了,程序启动时自己降级或报错退出;配置文件用的是相对路径,在 systemd 下工作目录不是你以为的那个。
状态三:Exit Code 比日志更早告诉你原因
status 里有这样一行:
Process: 1234 ExecStart=/opt/app/start.sh (code=exited, status=203/EXEC)
几个高频退出码:
| 退出码 | 含义 | 怎么查 |
|---|---|---|
| 203/EXEC | ExecStart 指向的文件不存在或没有执行权限 | ls -l 看路径与权限 |
| 1 | 程序自己报错退出 | 看应用日志 |
| 143 | 收到 SIGTERM 正常终止 | 一般是手动 stop 或部署脚本 |
| 137 | 被 SIGKILL 强杀,常见于 OOM | `dmesg |
如果 Main PID 每次看都不一样,说明程序在崩溃—重启循环里,此时日志才是主要线索。
状态四:启动太频繁会被限流
连续快速失败后,再 start 会报:
start request repeated too quickly
systemd 默认规则:10 秒内启动超过 5 次就拒绝执行。临时解除:
sudo systemctl reset-failed myapp
sudo systemctl start myapp
注意这只是让 start 能执行,根因还在崩溃循环里,必须回到状态三去看退出码和日志。清空计数不等于修好服务。
状态五:配置改了没生效,多半漏了 daemon-reload
改了 /etc/systemd/system/myapp.service 之后只执行 restart,systemd 用的还是内存里的旧配置。
正确顺序是:
sudo systemctl daemon-reload
sudo systemctl restart myapp
两个使用习惯值得养成:
systemctl cat myapp看实际生效的完整配置,包含所有 drop-in 覆盖,比翻目录靠谱- 想改配置用
sudo systemctl edit myapp,它会在/etc/systemd/system/myapp.service.d/建一个覆盖文件,不动原文件,后续包升级也不会被覆盖
另外两个高频误解:
enable只负责「下次开机自启」,不会立刻启动服务,启动必须startdisable只取消自启,不会停止正在运行的服务,停止必须stop
排障顺序(可直接复制)
systemctl --failed # 1. 有哪些服务失败
systemctl status myapp # 2. 看 Loaded 与 Active
journalctl -u myapp -n 100 --no-pager # 3. 看真实报错
systemctl show -p ExecStart myapp # 4. 核对启动命令
sudo systemctl daemon-reload # 5. 改过 unit 文件才需要
sudo systemctl reset-failed myapp # 6. 被限流过才需要
sudo systemctl start myapp
完整命令清单见 systemctl 服务管理速查。排查时如果想对比改过的 unit 文件差异,用 文本对比;想在日志里精确捞出关键行,用 正则测试 先把表达式验通。
定时任务写不出日志是另一类问题,可以看旧文 Linux 定时任务踩坑:为什么脚本跑了但日志没写。