Linux 内核在启动时,会预先分配一块固定大小的物理内存作为日志存储区域,采用**环形(循环覆盖)**的数据结构管理:
展开代码┌─────────────────────────────────────────┐ │ 内核环形缓冲区(Ring Buffer) │ │ 典型大小:256KB ~ 4MB(可配置) │ ├─────────────────────────────────────────┤ │ [消息1] [消息2] [消息3] ... [消息N] │ │ ▲ ▼ │ │ └──────── 新消息覆盖旧消息 ─────────┘ │ └─────────────────────────────────────────┘
核心特性:
| 特性 | 说明 | 影响 |
|---|---|---|
| 固定大小 | 不随日志量增长 | 高负载系统可能丢失早期日志 |
| 循环覆盖 | 满时新消息覆盖最旧消息 | 需及时导出或持久化重要日志 |
| 内核态存储 | 不依赖文件系统 | 文件系统损坏时仍可查看 |
| 无锁设计 | 多 CPU 并发写入 | 高性能,极低开销 |
查看缓冲区大小:
展开代码# 查看当前环形缓冲区大小(字节) cat /sys/kernel/debug/printk/buffer_size_kb # 或 dmesg | wc -c
展开代码硬件事件/驱动调用 │ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ printk() │───►│ 环形缓冲区 │◄───│ dmesg/journalctl │ │ 内核函数 │ │ (内存中) │ │ 用户态读取工具 │ └─────────────┘ └─────────────┘ └─────────────┘ │ ▼ ┌─────────────┐ │ /dev/kmsg │ │ 设备节点 │ └─────────────┘
展开代码# 基本输出(纯文本,无时间戳) dmesg # 显示可读时间戳(推荐) dmesg -T # [Mon Oct 27 17:15:23 2023] usb 1-1: new high-speed USB device number 2 using xhci_hcd # 显示时间间隔(距上一条日志的秒数) dmesg -d # [ 0.000000] Linux version 5.15.0-76-generic ← 启动 # [ 0.004567] Command line: BOOT_IMAGE=/vmlinuz... ← 4.5ms后
| 级别 | 名称 | 含义 | 使用场景 |
|---|---|---|---|
| 0 | emerg | 系统不可用 | 内核崩溃、panic |
| 1 | alert | 必须立即处理 | 严重硬件故障 |
| 2 | crit | 严重错误 | 关键服务失败 |
| 3 | err | 错误 | 驱动加载失败 |
| 4 | warn | 警告 | 配置异常、降级运行 |
| 5 | notice | 正常但重要 | 安全事件、状态变更 |
| 6 | info | 信息性 | 常规操作日志 |
| 7 | debug | 调试信息 | 开发诊断 |
展开代码# 仅显示错误和警告(生产排查首选) dmesg -l err,warn # 或完整写法 dmesg --level=err,warn # 显示所有严重级别 dmesg -l emerg,alert,crit,err,warn,notice,info,debug
展开代码# 自动分页 + 颜色高亮(类似 less) dmesg -H # 操作:↑/↓ 滚动,/ 搜索,q 退出 # 彩色输出(不自动分页) dmesg -L
展开代码# 仅监控新产生的日志(不显示历史) dmesg --follow-new # 或简写 dmesg -w # 与传统 tail -f 的区别: # tail -f /var/log/kern.log ← 依赖 rsyslog,可能有延迟 # dmesg --follow-new ← 直接读取 /dev/kmsg,实时性更高
展开代码# 搜索 USB 相关日志 dmesg | grep -i "usb" | tail -20 # 典型错误与解决方案: # ───────────────────────────────────────────────────────── # usb 1-1: device descriptor read/64, error -110 # → 原因:USB 设备响应超时(物理连接问题) # → 解决:更换 USB 端口、线缆,或检查设备供电 # # usb 1-1: device not accepting address 2, error -71 # → 原因:USB 协议错误(设备或控制器故障) # → 解决:尝试其他端口,更新 xhci_hcd 驱动 # # usbhid: probe of 1-1:1.0 failed with error -32 # → 原因:HID 驱动不兼容 # → 解决:卸载重载驱动:sudo modprobe -r usbhid && sudo modprobe usbhid
展开代码# 查看磁盘错误(以 sda 为例) dmesg -l err | grep "sda" # 关键错误模式: # ───────────────────────────────────────────────────────── # Buffer I/O error on dev sda, logical block 12345678 # → 物理坏块,立即备份数据,更换硬盘 # # EXT4-fs error (device sda1): ext4_lookup: deleted inode referenced # → 文件系统损坏,尝试 fsck 修复 # # ata1.00: exception Emask 0x0 SAct 0x0 SErr 0x40000000 action 0x6 frozen # → SATA 链路错误,检查数据线和电源
展开代码# 内存相关日志 dmesg | grep -iE "memory|oom|hardware.error" | tail -30 # 典型场景: # ───────────────────────────────────────────────────────── # Out of memory: Kill process 1234 (python) score 912 or sacrifice child # → OOM Killer 触发,进程被强制终止 # → 解决:增加物理内存、添加 Swap、优化应用内存使用 # # Hardware Error: Corrected error, no action required. # → ECC 内存自动纠正错误(可接受) # → 监控:若频繁出现,预示内存条老化 # # Hardware Error: Machine check events logged # → 不可纠正的硬件错误 # → 立即检查:mcelog --client 或 edac-util -v
展开代码# 网卡驱动日志 dmesg | grep -iE "eth|ens|wlan|network" | tail -20 # 典型问题: # ───────────────────────────────────────────────────────── # eth0: Link is Down # → 物理链路断开,检查网线、交换机端口 # # ixgbe 0000:01:00.0: NIC Link is Up 10 Gbps, Flow Control: RX/TX # → 网卡正常工作,10Gbps 链路已建立
展开代码# 导出完整日志到文件 dmesg > /var/log/dmesg-$(date +%F-%H%M).log # 导出带时间戳的日志 dmesg -T > /var/log/dmesg-readable.log # 定期归档(cron 任务) # /etc/cron.d/dmesg-backup 0 */6 * * * root /bin/dmesg -T > /var/log/dmesg-archive-$(date +\%F-\%H).log
| 特性 | dmesg | journalctl |
|---|---|---|
| 数据来源 | 内核环形缓冲区 | systemd-journald(内核+用户态) |
| 存储位置 | 内存(/dev/kmsg) | 内存(/run/log)或磁盘(/var/log) |
| 日志范围 | 仅内核日志 | 内核 + 所有 systemd 服务 |
| 持久化 | 需手动导出 | 原生支持持久化配置 |
| 查询能力 | 简单过滤 | 强大的结构化查询 |
| 性能 | 极高(直接内存访问) | 高(二进制索引) |
关键认知:journalctl 包含 dmesg 的内容,但 dmesg 不包含 journalctl 的用户态日志。
展开代码# 查看当前启动的所有日志(内核+服务) journalctl # 查看上一次启动 journalctl -b -1 # 查看特定启动(需启用持久化) journalctl --list-boots # -1 ... Mon 2023-10-23 09:15:23 CST—Mon 2023-10-23 18:30:45 CST # 0 ... Tue 2023-10-24 08:00:12 CST—Tue 2023-10-24 17:45:30 CST journalctl -b -2 # 查看上上次启动
展开代码# 绝对时间 journalctl --since "2023-10-27 17:15:00" --until "2023-10-27 18:00:00" # 相对时间 journalctl --since "1 hour ago" journalctl --since "yesterday" --until "today" journalctl --since "2023-10-01" --until "2 days ago" # 仅今天 journalctl --since today
展开代码# 查看特定服务 journalctl -u nginx.service journalctl -u sshd.service -f # 实时跟踪 # 查看多个服务 journalctl -u nginx.service -u php-fpm.service # 查看系统初始化(无服务单元) journalctl -p err -b # 启动错误
展开代码# 仅错误及以上(与 dmesg -l err 类似,但包含用户态) journalctl -p err # 优先级名称或数字 journalctl -p 3 # err journalctl -p warning # 4 journalctl -p 0..3 # emerg 到 err
展开代码# 按进程名 journalctl _COMM=nginx # 按可执行文件路径 journalctl _EXE=/usr/bin/python3 # 按 PID journalctl _PID=1234 # 按命令行参数(查找特定脚本) journalctl _CMDLINE="/usr/bin/python3 /app/server.py" # 按 syslog 标识 journalctl SYSLOG_IDENTIFIER=kernel # 等价于 dmesg
展开代码# 复杂条件:nginx 服务,昨天,错误级别 journalctl -u nginx.service --since yesterday -p err # 特定时间段 + 特定服务 + 实时跟踪 journalctl -u myapp.service --since "10 minutes ago" -f
展开代码# 详细输出(含所有元数据) journalctl -o verbose # JSON 格式(程序化解析) journalctl -u myapp -o json | jq '.MESSAGE' # 短格式(类似传统 syslog) journalctl -o short # 仅消息内容(无时间戳等) journalctl -o cat
默认情况下,systemd-journald 将日志存储在 内存中(/run/log/journal),重启后丢失。对于服务器故障排查,必须启用持久化存储。
展开代码# 步骤 1:创建持久化目录 sudo mkdir -p /var/log/journal # 步骤 2:重启服务(自动检测并迁移) sudo systemctl restart systemd-journald # 验证 ls -la /var/log/journal/ # 应出现类似:systemd-journald-a1b2c3d4e5f67890.journal
展开代码[Journal] # 存储模式:volatile(内存)、persistent(磁盘)、auto(自动检测) Storage=persistent # 磁盘空间限制(持久存储) SystemMaxUse=5G # 最大占用 5GB SystemKeepFree=10G # 保留 10GB 空闲空间 SystemMaxFileSize=100M # 单个日志文件最大 100MB # 内存限制(运行时) RuntimeMaxUse=500M # 内存中最多 500MB RuntimeMaxFileSize=50M # 运行时单个文件 50MB # 保留策略 MaxRetentionSec=1month # 保留 1 个月 MaxFileSec=1week # 单个文件最长 1 周 # 压缩 Compress=yes # 启用压缩,节省空间 # 转发到传统 syslog(兼容旧系统) ForwardToSyslog=yes
应用配置:
展开代码sudo systemctl restart systemd-journald
展开代码# 查看当前磁盘占用 journalctl --disk-usage # Archived and active journals take up 2.8G in the file system. # 按大小清理(保留最近 1GB) sudo journalctl --vacuum-size=1G # 按时间清理(保留最近 1 年) sudo journalctl --vacuum-time=1years # 按文件数清理(保留最近 10 个启动) sudo journalctl --vacuum-files=10
展开代码# 步骤 1:分析启动耗时 systemd-analyze blame # 3.456s NetworkManager-wait-online.service # 2.123s docker.service # 1.987s postgresql.service # 步骤 2:查看启动过程中的错误 journalctl -b -p err # 步骤 3:查看特定服务的详细启动日志 journalctl -u NetworkManager-wait-online.service -b # 步骤 4:结合 dmesg 查看硬件初始化 dmesg -l warn,err | grep -E "eth|wlan|nvme"
展开代码# 步骤 1:扩大日志范围(可能崩溃前已有异常) journalctl -u myapp.service --since "10 minutes ago" -p debug # 步骤 2:查看内核是否记录异常(OOM、段错误) dmesg -T | grep -E "killed|segfault|oom" # 步骤 3:查看 audit 日志(SELinux/AppArmor 拦截) sudo ausearch -ts recent -m avc
| 任务 | 推荐工具 | 命令 |
|---|---|---|
| 快速查看内核错误 | dmesg | dmesg -l err,warn -T |
| 实时跟踪内核日志 | dmesg | dmesg --follow-new |
| 查看服务完整生命周期 | journalctl | journalctl -u nginx.service |
| 分析启动问题 | journalctl | journalctl -b -p err |
| 跨重启追溯问题 | journalctl | journalctl -b -1 --since "10:00" |
| 导出结构化日志 | journalctl | journalctl -o json > logs.json |
| 高性能实时监控 | dmesg | dmesg -w(比 journalctl -k -f 更快) |
本文作者:zzz
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!