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 只负责「下次开机自启」,不会立刻启动服务,启动必须 start
  • disable 只取消自启,不会停止正在运行的服务,停止必须 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 定时任务踩坑:为什么脚本跑了但日志没写。