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.target | emergency.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 -h | OOM 会杀死进程 |
| 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
⚠️ 注意事项
- 生产环境谨慎操作:调试操作可能影响服务可用性
- 备份配置:修改 Unit 文件前先备份
- 日志轮转:定期清理旧日志,避免磁盘空间不足
- 核心转储安全:核心转储可能包含敏感信息
- SELinux/AppArmor:安全模块可能阻止服务访问资源
💡 提示
- 使用
journalctl -f实时查看日志,快速定位问题 systemd-analyze verify是检查 Unit 文件语法的最佳工具- 救援模式下可以修复大多数启动问题
- 使用
systemctl edit创建 override 配置,避免直接修改原始文件 coredumpctl debug可以快速进入 GDB 调试崩溃的程序