强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

systemd 教程 / 故障排查与调试

故障排查与调试

systemd 提供了丰富的调试和诊断工具,帮助管理员快速定位和解决服务问题。本章将介绍系统化的故障排查方法。


1. 服务启动失败分析

1.1 systemctl status

排查服务问题的第一步:

# 查看服务状态
systemctl status nginx.service

# 输出示例:
# ● nginx.service - The nginx HTTP and reverse proxy server
#      Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled)
#      Active: failed (Result: exit-code) since Mon 2026-05-11 10:30:45 CST; 5min ago
#     Process: 12345 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=1/FAILURE)
# May 11 10:30:45 webserver nginx[12345]: nginx: [emerg] unknown directive "server_name"
# May 11 10:30:45 webserver systemd[1]: nginx.service: Failed with result 'exit-code'.

1.2 常见失败状态

状态含义常见原因
failed (Result: exit-code)进程退出码非 0配置错误、依赖缺失
failed (Result: timeout)启动超时服务启动太慢、死锁
failed (Result: signal)收到信号段错误、OOM Killer
failed (Result: resources)资源不足内存不足、磁盘满
inactive (dead)服务未运行正常停止或未启动

1.3 详细状态信息

# 显示特定属性
systemctl show nginx.service -p ActiveState
systemctl show nginx.service -p MainPID
systemctl show nginx.service -p MemoryCurrent
systemctl show nginx.service -p ExecStart
systemctl show nginx.service -p Result

2. 日志排查

2.1 journalctl 基础

# 查看服务日志
journalctl -u nginx.service

# 实时查看
journalctl -u nginx.service -f

# 查看最近 100 行
journalctl -u nginx.service -n 100

# 查看今天的日志
journalctl -u nginx.service --since today

# 查看指定时间范围
journalctl -u nginx.service --since "2026-05-11 10:00" --until "2026-05-11 11:00"

# 查看上次启动的日志
journalctl -u nginx.service -b -1

2.2 日志过滤

# 按优先级过滤
journalctl -u nginx.service -p err      # 仅错误
journalctl -u nginx.service -p warning  # 警告及以上
journalctl -u nginx.service -p debug    # 调试及以上

# 优先级说明
# emerg (0) - 系统不可用
# alert (1) - 需要立即处理
# crit  (2) - 严重条件
# err   (3) - 错误
# warning(4) - 警告
# notice (5) - 正常但重要
# info  (6) - 信息
# debug (7) - 调试

# 输出 JSON 格式
journalctl -u nginx.service -o json

2.3 内核日志

# 查看内核日志
dmesg -T  # 显示人类可读时间戳

# 查看 OOM Killer 日志
dmesg | grep -i "out of memory"

# 查看磁盘错误
dmesg | grep -i "error\|fail" | grep -i "disk\|ata\|scsi"

3. Unit 文件验证

3.1 systemd-analyze verify

# 验证单个 unit 文件
systemd-analyze verify /etc/systemd/system/nginx.service

# 验证所有 unit 文件
systemd-analyze verify

# 输出示例(有错误时):
# /etc/systemd/system/myapp.service:9: Unknown lvalue 'RestartMax' in section 'Service'
# /etc/systemd/system/myapp.service:12: Executable path is not absolute: nginx

3.2 常见配置错误

错误原因修复
Unknown lvalue不认识的配置项检查拼写和语法
Executable path is not absolute路径不是绝对路径使用完整路径如 /usr/sbin/nginx
Failed to create unit文件格式错误检查文件编码和换行符
Dependency failed依赖服务未找到检查依赖服务名称

4. 核心转储管理

4.1 配置 core dump

# 查看当前 core dump 配置
cat /proc/sys/kernel/core_pattern

# 配置 systemd-coredump
echo "kernel.core_pattern=|/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %h" | \
    sudo tee /etc/sysctl.d/50-coredump.conf
sudo sysctl -p /etc/sysctl.d/50-coredump.conf

4.2 查看和分析 core dump

# 列出所有 core dump
coredumpctl list

# 查看特定进程的 core dump
coredumpctl list nginx

# 查看 core dump 信息
coredumpctl info 12345

# 使用 GDB 调试
coredumpctl debug 12345

# 导出 core dump
coredumpctl dump 12345 -o /tmp/core.nginx

4.3 在服务中启用 core dump

[Service]
LimitCORE=infinity

5. 调试 Shell

5.1 使用 ExecStart=/bin/bash

临时修改服务启动命令进行调试:

# 1. 创建 override 配置
sudo systemctl edit nginx.service

# 2. 添加以下内容
[Service]
ExecStart=
ExecStart=/bin/bash -c 'echo "Debug mode"; exec /usr/sbin/nginx -g "daemon off;"'

# 3. 重新加载并重启
sudo systemctl daemon-reload
sudo systemctl restart nginx.service

5.2 调试启动脚本

#!/bin/bash
set -x  # 启用调试模式
set -e  # 遇到错误立即退出

echo "Starting application..."
echo "User: $(whoami)"
echo "Working directory: $(pwd)"
exec /opt/myapp/bin/myapp

6. systemd 调试级别

6.1 临时调整日志级别

# 设置调试级别
sudo systemctl log-level debug

# 恢复正常级别
sudo systemctl log-level info

# 可用级别:emerg, alert, crit, err, warning, notice, info, debug

6.2 启动时调试

# 通过内核参数启用调试
sudo grubby --update-kernel=ALL --args="systemd.log_level=debug systemd.log_target=kmsg"

7. systemd.confirm_spawn 内核参数

# 启用确认模式
sudo grubby --update-kernel=ALL --args="systemd.confirm_spawn=1"

# 重启后,systemd 每次创建进程都会提示确认

⚠️ 注意:启用 systemd.confirm_spawn 会导致启动过程需要人工交互,仅用于调试。


8. 启动救援模式

8.1 rescue.target

# 启动到救援模式
sudo systemctl isolate rescue.target

# 或通过内核参数
sudo grubby --update-kernel=ALL --args="systemd.unit=rescue.target"

8.2 emergency.target

# 启动到紧急模式
sudo systemctl isolate emergency.target

8.3 救援模式 vs 紧急模式

特性rescue.targetemergency.target
文件系统全部挂载仅根(只读)
网络不启动不启动
系统服务基本服务最小化
适用场景一般故障严重故障

8.4 在救援模式下修复

# 进入救援模式后

# 检查并修复文件系统
fsck /dev/sda1

# 修复引导配置
grub2-install /dev/sda
grub2-mkconfig -o /boot/grub2/grub.cfg

# 重置密码
passwd root

# 重启
systemctl reboot

9. 常见故障及解决

9.1 Dependency failed

症状Dependency failed for myapp.service

排查

systemctl list-dependencies myapp.service
systemctl status mysql.service
journalctl -u mysql.service

解决:将 Requires 改为 Wants(弱依赖),或确保依赖服务正常。

9.2 Timeout

症状myapp.service: Start operation timed out. Terminating.

排查

systemctl show myapp.service -p TimeoutStartUSec
journalctl -u myapp.service --since "5 minutes ago"

解决

[Service]
TimeoutStartSec=300
# 或使用 Type=notify
Type=notify

9.3 Crash Loop

症状:服务反复重启

排查

systemctl show myapp.service -p NRestarts
journalctl -u myapp.service -b --reverse | head -50
coredumpctl list | grep myapp

解决

sudo systemctl reset-failed myapp.service
[Service]
Restart=on-failure
RestartSec=10
StartLimitBurst=5
StartLimitIntervalSec=300

9.4 Permission Denied

症状Failed at step EXEC spawning /opt/myapp/bin/myapp: Permission denied

排查

ls -la /opt/myapp/bin/myapp
ls -laZ /opt/myapp/bin/myapp  # SELinux 上下文

解决

chmod +x /opt/myapp/bin/myapp
restorecon -Rv /opt/myapp/  # 修复 SELinux 上下文

9.5 Port Already in Use

症状bind() to 0.0.0.0:80 failed (98: Address already in use)

排查

ss -tlnp | grep :80
fuser 80/tcp

解决

sudo fuser -k 80/tcp

10. 调试 Checklist

10.1 系统级排查

检查项命令说明
磁盘空间df -h磁盘满会导致服务异常
内存使用free -hOOM 会杀死进程
CPU 负载uptime负载过高影响服务
文件描述符cat /proc/sys/fs/file-nr耗尽会导致连接失败
网络连接ss -tlnp端口冲突
系统日志journalctl -b -p err系统级错误

10.2 快速修复步骤

# 1. 查看服务状态
systemctl status myapp.service

# 2. 查看服务日志
journalctl -u myapp.service -n 50

# 3. 验证配置文件
systemd-analyze verify /etc/systemd/system/myapp.service

# 4. 检查依赖
systemctl list-dependencies myapp.service

# 5. 尝试手动启动
sudo -u myapp /opt/myapp/bin/myapp --debug

# 6. 查看系统日志
journalctl -b -p err

# 7. 检查资源
df -h && free -h && uptime

# 8. 重置并重启
sudo systemctl reset-failed myapp.service
sudo systemctl restart myapp.service

⚠️ 注意事项

  1. 生产环境谨慎操作:调试操作可能影响服务可用性
  2. 备份配置:修改 Unit 文件前先备份
  3. 日志轮转:定期清理旧日志,避免磁盘空间不足
  4. 核心转储安全:核心转储可能包含敏感信息
  5. SELinux/AppArmor:安全模块可能阻止服务访问资源

💡 提示

  • 使用 journalctl -f 实时查看日志,快速定位问题
  • systemd-analyze verify 是检查 Unit 文件语法的最佳工具
  • 救援模式下可以修复大多数启动问题
  • 使用 systemctl edit 创建 override 配置,避免直接修改原始文件
  • coredumpctl debug 可以快速进入 GDB 调试崩溃的程序

扩展阅读