用 journalctl 五分钟定位 Linux 服务启动失败的原因
服务起不来的时候,很多人的第一反应是反复 systemctl restart 碰运气。其实 systemd 已经把每一次启动的完整过程都记在了日志里,用好 journalctl,五分钟就能从日志里揪出服务启动失败的真正原因。
一、先看一眼:服务到底是怎么失败的
systemctl status nginx.service
重点看两处:
Active行:failed (Result: exit-code)表示进程启动后异常退出;failed (Result: timeout)表示启动超时;failed (Result: signal)表示被信号杀死(比如 OOM)。- 页面最后几行:systemd 打印的最近日志,往往已经写明了失败原因。
二、用 journalctl 抓出完整的启动日志
systemd 为每个服务维护了独立的日志流,-u 参数只过滤目标服务:
# 查看 nginx 服务的全部日志
journalctl -u nginx.service --no-pager
# 只看最近 20 行,快速定位
journalctl -u nginx.service -n 20 --no-pager
# 只看错误级别以上的日志,过滤噪音
journalctl -u nginx.service -p err --no-pager
# 实时跟踪,然后在另一个终端复现一次启动失败
journalctl -u nginx.service -f
-p err 是最常用的降噪手段:只保留 error、crit、alert、emerg 级别,几百行日志一下就收敛到关键的几行。
三、五分钟排查清单
按这个顺序走,九成启动失败都能定位:
1. 看退出码
journalctl -u myapp.service | grep -i "code="
常见含义:exit-code=1 多半是配置错误;203 表示可执行文件不存在(路径写错);127 表示命令找不到。
2. 验配置文件
很多服务在配置语法错误时直接拒绝启动,先做预检:
nginx -t # 检查 nginx 配置
mysqld --validate-config # 检查 MySQL 配置
3. 查端口占用
ss -tlnp | grep 80
如果端口被旧进程或别的服务占用,新实例 bind 失败是启动失败的头号原因。
4. 查权限
journalctl -u myapp.service | grep -i "permission denied"
注意两类权限问题:文件系统权限,以及 SELinux / AppArmor 的拦截,后者在日志里常以 avc: denied 出现。
5. 查依赖
systemctl list-dependencies myapp.service
依赖的网络目标或磁盘挂载没就绪,也会把启动拖垮。After= 写得不严谨的服务在开机自启时最容易踩这个坑。
四、实战:一次真实的定位过程
某天发布后 nginx 起不来:
$ systemctl status nginx
Active: failed (Result: exit-code)
$ journalctl -u nginx -p err --no-pager
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
日志直接点名:80 端口被占用。ss -tlnp | grep :80 找到残留的旧 worker 进程,kill 掉之后 systemctl start nginx,服务恢复。从发现异常到恢复,全程不到两分钟。
五、几个好用的组合技
# 按时间窗口查:今天凌晨 2:30 到 3:30 的日志
journalctl -u mysql --since "2026-11-02 02:30" --until "2026-11-02 03:30"
# 只看本次开机以来的日志
journalctl -u redis -b --no-pager
# 内核视角:OOM、磁盘错误这类底层问题
journalctl -k -p err --no-pager
六、小结
记住这个固定顺序:systemctl status 看失败类型 → journalctl -u 看完整日志 → -p err 过滤噪音 → 按端口、权限、配置、依赖逐项排查。把这套流程练熟,下次服务起不来,你就是团队里五分钟定位问题的那个人。
- 点赞
- 收藏
- 关注作者
评论(0)