43 - 系统错误排查与日志分析

系统出了问题不可怕,可怕的是不知道如何找到问题所在。本章系统地讲解 Linux 错误排查方法论,从 journalctl 深度使用到启动修复,从硬件诊断到进程调试,帮助你建立从发现问题到定位根源再到实施修复的完整排查能力。


43.1 系统排查方法论

排查问题应遵循系统性的思维流程:

1. 复现问题 → 明确问题的触发条件和场景
2. 缩小范围 → 确定问题所属层级(硬件→内核→驱动→服务→应用)
3. 查看日志 → journalctl、dmesg、应用日志
4. 提出假设 → 基于已有信息推测根因
5. 尝试修复 → 从最小改动开始,一次只改一个变量
6. 验证结果 → 确认问题已解决且无副作用
7. 记录方案 → 供日后参考和团队共享

排查核心原则

原则说明
最近改了什么问题通常出现在最近的变更之后
二分法逐步缩小范围,排除无关变量
最小复现用最简单的方式复现问题
先看日志日志是最重要的第一手线索
一次只改一个避免同时修改多个变量导致无法归因

速查命令表

场景命令
总览uptime, who, last, dmesg -H
系统启动日志journalctl -b
上次启动日志journalctl -b -1
只看错误journalctl -b -p err
服务状态systemctl status service
失败服务systemctl --failed
磁盘空间df -h, du -sh /path
内存使用free -h, vmstat 1
CPU 负载top, htop, uptime
开放端口ss -tulnp
文件占用lsof /path/to/file
启动耗时systemd-analyze blame

43.2 journalctl 深入使用

journalctl 是 systemd 的日志查询工具,是排查问题的第一利器。

基本过滤

# 查看本次启动的所有日志
journalctl -b
 
# 查看上次启动的日志(排查"为什么上次关机/重启失败")
journalctl -b -1
 
# 列出所有可查询的启动记录
journalctl --list-boots
 
# 实时跟踪日志(类似 tail -f)
journalctl -f
 
# 按时间过滤
journalctl --since "2024-07-24 10:00:00"
journalctl --since "2024-07-24" --until "2024-07-25"
journalctl --since "1 hour ago"
journalctl --since "30 min ago"
journalctl --since yesterday

按服务和优先级过滤

# 查看特定服务的日志
journalctl -u nginx
journalctl -u sshd
 
# 多服务合并查看
journalctl -u nginx -u php-fpm
 
# 实时跟踪服务日志
journalctl -u docker -f
 
# 按日志优先级过滤
# emerg(0) > alert(1) > crit(2) > err(3) > warning(4) > notice(5) > info(6) > debug(7)
journalctl -b -p err # 错误及以上
journalctl -b -p warning # 警告及以上
journalctl -b -p warning..err # 警告到错误范围
 
# 按 PID 过滤
journalctl _PID=1234
 
# 按 UID 过滤
journalctl _UID=1000
 
# 按可执行文件过滤
journalctl /usr/bin/python

内核日志

# 只看内核消息(等同于 dmesg)
journalctl -k
journalctl -k -b # 本次启动的内核日志
journalctl --dmesg

日志持久化配置

默认情况下,journald 日志存储在内存(/run/log/journal/)中,重启后丢失。持久化配置:

# 创建持久化目录
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
# 重启 systemd-journald 生效

编辑 /etc/systemd/journald.conf

[Journal]
Storage=persistent
Compress=yes
SystemMaxUse=500M
SystemMaxFileSize=50M
MaxRetentionSec=1month
# 查看日志占用空间
journalctl --disk-usage
 
# 清理日志
sudo journalctl --vacuum-time=2d # 仅保留最近 2 天
sudo journalctl --vacuum-size=500M # 限制总大小 500M
sudo journalctl --vacuum-files=5 # 保留最近 5 个日志文件

高级输出格式

# JSON 格式
journalctl -o json
journalctl -o json-pretty
 
# 只输出消息体
journalctl -o cat
 
# 配合 jq 精确提取
journalctl -o json | jq 'select(.PRIORITY == "3") | .MESSAGE'
 
# 导出日志
journalctl -b > /tmp/boot_log.txt
journalctl -u nginx -o json > /tmp/nginx_log.json

43.3 dmesg 内核日志分析

dmesg 显示内核环形缓冲区的消息,主要包含硬件检测、驱动加载、内核 Oops/Panic 等信息。

# 查看内核日志
dmesg -H # 人类可读格式(时间戳 + 颜色)
dmesg -T # 显示可读时间戳
dmesg -w # 实时跟踪(类似 tail -f)
 
# 按级别过滤
dmesg -l err
dmesg -l err,warn
 
# 按设施过滤
dmesg -f kern # 内核消息
dmesg -f daemon # 守护进程消息
 
# 常用关键词搜索
dmesg | grep -i error
dmesg | grep -i fail
dmesg | grep -i "out of memory"
dmesg | grep -i firmware
dmesg | grep -iE "(sda|nvme|ata)" # 存储设备
dmesg | grep -iE "(drm|gpu|i915|amdgpu|nvidia)" # GPU
dmesg | grep -i usb

43.4 启动故障排查

启动卡住 / Kernel Panic

# 查看上次启动的紧急级别日志
journalctl -b -1 -p emerg
journalctl -b -1 -p crit
 
# 常见的启动失败原因和应对:
# 1. 内核模块不兼容 → 安装并使用 LTS 内核作为后备
# 2. 文件系统损坏 → 从 Live USB 启动后执行 fsck
# 3. initramfs 缺少模块 → 重建 initramfs
# 4. fstab 配置错误 → 进入救援模式修复
 
# 启动时在 GRUB 中添加调试参数(按 e 编辑):
# 移除 quiet,添加 systemd.log_level=debug

救援模式与紧急模式

# 救援模式(基本服务已启动,文件系统读写挂载)
# 在 GRUB 菜单按 e,在 linux 行末尾添加:
# systemd.unit=rescue.target
 
# 紧急模式(最小化,根文件系统只读)
# 添加:systemd.unit=emergency.target
 
# 在紧急模式下修复:
mount -o remount,rw / # 重新挂载为读写
mount -a # 挂载 fstab 中所有分区
# 编辑配置修复问题后:
exit # 继续启动

无法进入图形界面

# 切换到 TTY(Ctrl+Alt+F2 ~ F6)
 
# 检查显示管理器状态
systemctl status gdm # GNOME
systemctl status sddm # KDE
systemctl status lightdm # LightDM
 
# 查看 Xorg 日志
cat /var/log/Xorg.0.log | grep "(EE)" # EE = 错误
 
# 常见原因:
# 1. 显卡驱动问题 → 重新安装驱动
# 2. 配置冲突 → 移除 /etc/X11/xorg.conf 配置文件
# 3. 权限问题 → rm ~/.Xauthority 并重新登录

文件系统问题

# fstab 配置错误导致无法挂载
# 在紧急模式下修复:
mount -o remount,rw /
nano /etc/fstab
# 检查 UUID 是否正确:blkid
# 非关键分区添加 nofail 选项防止阻止启动
 
# 文件系统损坏
sudo umount /dev/sda1 # 先卸载
sudo e2fsck -f /dev/sda1 # ext4
sudo xfs_repair /dev/sda1 # XFS
sudo btrfs check /dev/sda1 # Btrfs

使用 Live USB 修复

# 1. 从安装介质启动
 
# 2. 挂载系统分区
mount /dev/sda2 /mnt # 根分区
mount /dev/sda1 /mnt/boot # 启动分区
mount /dev/sda1 /mnt/boot/efi # ESP(如分开)
 
# 3. chroot 进入
mount -t proc /proc /mnt/proc
mount -t sysfs /sys /mnt/sys
mount --rbind /dev /mnt/dev
chroot /mnt /bin/bash
 
# 4. 在 chroot 中修复
# 重装内核
apt reinstall linux-image-$(uname -r) # Debian/Ubuntu
dnf reinstall kernel # Fedora
 
# 重建 initramfs
update-initramfs -u -k all # Debian/Ubuntu
dracut --force --kver $(uname -r) # Fedora/RHEL
mkinitcpio -P # Arch
 
# 修复 GRUB
grub-install --target=x86_64-efi --efi-directory=/boot/efi
grub-mkconfig -o /boot/grub/grub.cfg
 
# 5. 退出并重启
exit
umount -R /mnt
reboot

43.5 服务故障排查

# 查看失败的服务
systemctl --failed
 
# 查看特定服务的详细状态
systemctl status nginx
# 关键信息:Load state, Active state, Exit code
 
# 查看服务的完整日志
journalctl -u nginx --no-pager
 
# 查看服务启动依赖链
systemctl list-dependencies nginx
systemctl list-dependencies --reverse nginx
 
# 查看服务的启动耗时
systemd-analyze blame | grep nginx
 
# 重置失败状态(清除红点标记)
sudo systemctl reset-failed nginx
 
# 查看服务文件
systemctl cat nginx
 
# 编辑服务文件的 override
sudo systemctl edit nginx

43.6 硬件故障排查

磁盘 SMART 检测

# 安装
sudo apt install smartmontools
 
# 快速健康检查
sudo smartctl -H /dev/sda
 
# 完整 SMART 信息
sudo smartctl -a /dev/sda
 
# 关键 SMART 属性
# ID 5: Reallocated Sector Count > 0 需警惕
# ID 187: Reported Uncorrectable > 0 需警惕
# ID 197: Current Pending Sector > 0 需关注
# ID 198: Offline Uncorrectable > 0 需关注
 
# 短时自检(约 2 分钟)
sudo smartctl -t short /dev/sda
 
# 长时自检(可能数小时)
sudo smartctl -t long /dev/sda
 
# 查看自检结果
sudo smartctl -l selftest /dev/sda
 
# NVMe SMART
sudo smartctl -a /dev/nvme0
sudo nvme smart-log /dev/nvme0

内存测试

# 使用 memtester(在线测试)
sudo apt install memtester
sudo memtester 1024M 2 # 测试 1GB 内存,2 次
 
# 使用 memtest86+(离线测试,更彻底)
# 通过发行版包或 Live USB 启动

CPU 温度与性能

# 安装传感器工具
sudo apt install lm-sensors
sudo sensors-detect
sensors
 
# 持续监控
watch -n 1 sensors
 
# CPU 频率
cat /proc/cpuinfo | grep "MHz" | head
 
# 压力测试
sudo apt install stress
stress --cpu $(nproc) --timeout 60 &
watch -n 1 sensors

43.7 网络故障排查

# 基本连通性
ping -c 4 8.8.8.8 # 测试网络可达性
ping -c 4 google.com # 测试 DNS 是否正常
 
# DNS 诊断
nslookup google.com
dig google.com
resolvectl status # systemd-resolved 状态
 
# 网络接口状态
ip addr show
ip link show
 
# 路由表
ip route show
 
# 活跃连接和端口
ss -tulnp
ss -t state established
 
# 端口测试
nc -zv server.com 443 # TCP 端口是否开放
 
# 路由追踪
traceroute google.com
mtr google.com # 可视化 + 丢包统计
 
# 抓包分析
sudo tcpdump -i eth0 -n port 80
sudo tcpdump -i any -w /tmp/capture.pcap
 
# NetworkManager 日志
journalctl -u NetworkManager -f

常见网络问题速查

症状可能原因排查命令
完全无网络网卡未启用ip link show, rfkill list
能 ping IP 不能 ping 域名DNS 配置错误resolvectl status, cat /etc/resolv.conf
连接被拒绝防火墙 / 服务未监听sudo iptables -L -n, ss -tulnp
间歇性断连无线网卡电源管理iw dev wlan0 get power_save
速度慢链路协商问题ethtool eth0 | grep Speed

43.8 包管理故障

通用问题

# 数据库锁定(确认无其他包管理进程后删除锁文件)
# Debian/Ubuntu:
sudo rm /var/lib/dpkg/lock-frontend
sudo rm /var/lib/apt/lists/lock
# Fedora:
sudo rm /var/lib/rpm/.rpm.lock
# Arch:
sudo rm /var/lib/pacman/db.lck
 
# 依赖问题
# Debian/Ubuntu: 修复损坏的依赖
sudo apt --fix-broken install
# Fedora:
sudo dnf distro-sync
# Arch: 部分升级导致的库不匹配
sudo pacman -Syu # 完成完整升级
 
# 清理缓存
# Debian/Ubuntu: sudo apt clean
# Fedora: sudo dnf clean all
# Arch: sudo pacman -Sc
 
# 验证已安装包的文件完整性
# Debian/Ubuntu: dpkg --verify
# Fedora: rpm -Va
# Arch: paccheck(需安装 pacutils)

时间不同步导致签名验证失败

# 同步时间
sudo timedatectl set-ntp true
sudo hwclock --systohc
 
# 检查时间状态
timedatectl status

43.9 strace 与 ltrace 调试

strace:系统调用跟踪

# 安装
sudo apt install strace # Debian/Ubuntu
sudo dnf install strace # Fedora
 
# 跟踪程序执行的系统调用
strace ls
 
# 跟踪正在运行的进程
sudo strace -p 1234
 
# 只跟踪特定类别的系统调用
strace -e trace=open,read,write ls # 文件 I/O
strace -e trace=network curl example.com # 网络相关
strace -e trace=file ls # 文件操作
strace -e trace=%process command # 进程管理
 
# 统计系统调用次数和耗时
strace -c ls
 
# 显示时间信息
strace -tt ls # 微秒级时间戳
strace -T ls # 每个调用的耗时(尖括号内)
 
# 跟踪子进程
strace -f bash -c 'ls | grep txt'
 
# 查找程序打开的配置文件
strace -e trace=openat program 2>&1 | grep -v ENOENT
 
# 定位程序启动缓慢的原因
strace -T -e trace=file program 2>&1 | sort -t= -k2 -rn | head
 
# 查看程序为什么失败(关注 Permission Denied)
strace -e trace=openat program 2>&1 | grep "ENOENT\|EACCES"

ltrace:库函数调用跟踪

# 安装
sudo apt install ltrace
 
ltrace ls
ltrace -e malloc+free ls # 只跟踪内存分配
ltrace -c ls # 统计库调用
sudo ltrace -p 1234 # 跟踪运行中进程

43.10 coredump 分析

当程序崩溃时,systemd-coredump 自动收集核心转储文件。

# 列出所有 coredump
coredumpctl list
 
# 查看最近的 coredump 详情
coredumpctl info
 
# 查看特定程序的 coredump
coredumpctl info firefox
 
# 使用 GDB 分析
coredumpctl gdb firefox
# (gdb) bt # 查看堆栈回溯
# (gdb) bt full # 完整堆栈(含局部变量)
# (gdb) info threads # 线程信息
# (gdb) thread apply all bt # 所有线程堆栈
 
# 导出 coredump 文件
coredumpctl dump firefox -o /tmp/firefox.core
 
# 配置 coredump(/etc/systemd/coredump.conf)
# [Coredump]
# Storage=external
# Compress=yes
# ProcessSizeMax=2G
# MaxUse=1G

43.11 lsof 文件占用排查

# 安装
sudo apt install lsof
 
# 列出所有打开文件(输出通常极长)
lsof
 
# 特定用户打开的文件
lsof -u username
 
# 特定进程打开的文件
lsof -p 1234
 
# 哪些进程打开了特定文件
lsof /path/to/file
 
# 哪些进程在使用特定端口
lsof -i :80
lsof -i :443
lsof -i TCP
lsof -i TCP@192.168.1.1
 
# 目录下被打开的所有文件
lsof +D /var/log
 
# 已删除但尚未释放的文件(占用磁盘空间)
lsof | grep deleted

lsof 最常见的实用场景:umount 失败时找出哪些进程仍在访问挂载点下的文件。


43.12 日志文件位置速查

日志位置内容
journalctl 或其持久化目录系统日志(systemd 系统)
/var/log/syslog / /var/log/messages传统 syslog 日志
/var/log/auth.log / /var/log/secure认证和安全日志
/var/log/kern.log内核日志
/var/log/boot.log系统启动记录
/var/log/dpkg.log / /var/log/dnf.log包管理日志
/var/log/Xorg.0.logXorg 显示服务日志
~/.xsession-errors用户会话错误
/var/log/apache2/ / /var/log/nginx/Web 服务器日志

43.13 搜索资源的技巧

当遇到未知错误时,有效地搜索解决方案至关重要:

1. 提取关键错误信息(不是 "程序无法启动",而是精确的错误消息)
2. 搜索时用引号包裹精确错误:
 "error while loading shared libraries: libssl.so.1.1"
3. 限定搜索范围:
 site:wiki.archlinux.org touchpad not working
 site:wiki.debian.org nvidia driver
4. 查看文档的 Troubleshooting 章节
5. 关注帖子的 [SOLVED] 标记
6. man 和 --help 是第一手文档

交叉链接:系统性能深入分析参考 39-系统调优与性能分析。服务管理参考 11-systemd服务管理。引导流程问题参考 40-引导流程与GRUB。备份与恢复策略参考 17-备份与恢复