Linux 下用 journalctl 排查服务启动失败的 5 个实用技巧
服务在 systemd 管理下启动失败时,反复执行 systemctl restart 通常只会把同一条错误再刷一遍。更有效的做法是把 journalctl 当成一条带时间的证据链来读。下面五个技巧不依赖图形界面,适合云主机、本地虚拟机和容器宿主机,也是我排障时固定会走的顺序。
一、先把范围锁到单个单元和本次开机
systemctl status 只给出摘要,上下文在日志里。先运行:
journalctl -u myapp.service -b --no-pager
参数 -u 把输出收窄到指定单元,-b 只保留本次开机之后的记录,避免上周的旧报错混进来。如果机器已经重启过,改用 journalctl -u myapp.service -b -1 查看上一次启动。看到 Failed with result 时,把失败时间记下来,后面的过滤都围绕这个时间点,而不是从文件开头重读。
二、用优先级把噪声压下去
默认级别里 info 太多,真正的退出原因容易被冲掉。加上 -p err,或者先放宽到 warning:
journalctl -u myapp.service -p err -n 80 --no-pager
-n 限制条数,方便贴进工单。若异常被包在很长的多行堆栈里,可以加 -o cat 只看消息正文;需要和监控曲线对齐时,改用 -o short-iso,时间会精确到秒。不要一上来就用 -o json,那是给程序消费的,人读起来更慢。
三、按时间窗口回放,而不是从开机一直翻
如果大概知道失败发生在上午十点一刻,就切一个略宽的窗口:
journalctl -u myapp.service --since "2026-10-24 10:10:00" --until "2026-10-24 10:20:00" --no-pager
窗口要比故障时刻前后各多留几分钟。数据库、域名解析或网卡就绪的报错,常常出现在主进程退出之前几十秒;窗口太窄,会把真正的根因留在切片外面。时间字符串用引号包起来,避免空格被 shell 拆开。
四、辨认重启风暴,不要只看最后一行
同一秒内反复出现 Started 和 Stopped,多半是 Restart=on-failure 在空转。用下面的命令看重启计数和启动上限:
systemctl show myapp.service -p NRestarts -p StartLimitBurst -p Result
当 NRestarts 很快顶到上限,日志末尾往往只剩 start-limit-hit。这行只说明“不再尝试”,第一份真正的错误在更早的那一次退出里。往前翻到第一次非零退出码,再结合 ExecStart 的路径检查配置文件、工作目录和权限。权限问题在 journal 里经常写成 status=203/EXEC 或 status=217/USER,看到这两种码就去核对 User=、Group= 以及二进制是否存在。
五、把本次失败导出成可以转发的文本
确认范围之后再导出,避免把整机日志都拷走:
journalctl -u myapp.service -b -p info --no-pager > /tmp/myapp-boot.txt
文本比截图完整,同事也能搜索关键字。导出前先看一眼有没有口令或访问密钥被应用打进标准输出。如果有,先在配置里关掉 debug 或降低日志级别,再重新采集,不要把含密钥的文件贴到论坛或工单。
额外一条习惯:已经知道单元名时,坚持用 -u 加 -b;只有完全不知道是谁失败时,才使用 journalctl -xe 这种全局视图。全局视图适合“服务名都不清楚”的第一分钟,知道名字之后继续翻全机日志,只会把时间浪费在无关单元上。把这五步走完,大多数启动失败都能收敛到一条明确的退出原因。
- 点赞
- 收藏
- 关注作者
评论(0)