3、内核日志分析:dmesg命令详解、内核环形缓冲区、内核日志级别

内核日志,说白了就是Linux内核的“黑匣子”。系统启动时干了什么、驱动加载顺不顺利、硬件有没有报错,全记在里面。我干了这么多年运维,每次排查启动故障,第一件事就是敲dmesg。这章咱们就把这块彻底吃透。

3.1 内核环形缓冲区:有限空间里的循环记录

内核日志存在哪?不是普通文件,而是一个环形缓冲区(Ring Buffer)。你可以把它想象成一个固定大小的圆环,新消息不断往里写,写满了就覆盖最旧的那条。

核心特点:

  • 缓冲区大小固定(通常128KB~2MB,取决于内核配置)
  • 新日志覆盖旧日志,不会无限增长
  • 系统运行时始终在内存中,掉电即失
  • 可通过dmesg命令读取

为什么会设计成环形?我猜你也能想到——内核不能因为写日志把自己写死。如果日志无限增长,内存迟早爆掉。环形缓冲区保证了写操作永远是O(1)的,性能开销极小。

我曾经遇到一个案例:某台服务器跑了快两年没重启,查启动日志时发现最早的记录只剩最近几小时的了。嗯,缓冲区被填满循环了。所以记住——dmesg只能看到当前会话的日志,想看历史启动记录,得靠journalctl -k或/var/log/kern.log。

3.2 dmesg命令详解:不只是看一眼

大多数人用dmesg就是直接敲,然后被满屏信息淹没。其实这命令有不少实用选项,我一个个说。

3.2.1 基本用法

# 查看所有内核日志
dmesg

# 实时监控新日志(类似tail -f)
dmesg -w

# 只看最后20条
dmesg | tail -20

# 清空缓冲区(需要root)
dmesg -c

我个人习惯用dmesg -w配合插拔硬件做测试。比如你插个U盘,这边立刻就能看到内核识别设备的过程,非常直观。

3.2.2 按级别过滤

这才是dmesg的进阶用法。内核日志有8个级别,你可以只关注某个级别以上的消息。

# 只看错误级别(3级以上)
dmesg -l err

# 只看警告和错误
dmesg -l warn,err

# 只看调试信息
dmesg -l debug

小技巧:我排查启动故障时,习惯先跑dmesg -l err,crit,alert,emerg,把最严重的错误先揪出来。别一上来就看全部,信息太多反而抓不住重点。

3.2.3 按时间过滤

# 显示人类可读的时间戳
dmesg -T

# 只看最近1分钟的日志
dmesg -T | grep "$(date +'%H:%M' -d '1 minute ago')"

注意-T选项把内核启动后的秒数转成了系统时间。但有个坑——如果系统时间在启动后被修改过,这个转换就不准了。我遇到过NTP同步后时间跳变,导致dmesg时间戳对不上的情况。

3.3 内核日志级别:从KERN_EMERG到KERN_DEBUG

内核日志有8个级别,数字越小越严重。我整理了一张表,你存着随时查。

级别 数值 宏定义 含义 典型场景
0 KERN_EMERG 紧急 系统不可用 内核panic、致命硬件错误
1 KERN_ALERT 警报 必须立即处理 系统即将崩溃、严重资源耗尽
2 KERN_CRIT 临界 严重错误 磁盘故障、内存校验失败
3 KERN_ERR 错误 一般错误 驱动加载失败、设备I/O错误
4 KERN_WARNING 警告 潜在问题 驱动兼容性警告、资源使用率过高
5 KERN_NOTICE 通知 正常但重要 系统启动完成、服务状态变更
6 KERN_INFO 信息 一般信息 硬件检测、驱动版本信息
7 KERN_DEBUG 调试 调试信息 开发阶段、问题定位

你想想看,这8个级别其实对应了不同的“紧急程度”。0级是“系统要挂了”,7级是“开发人员自己看的”。实际运维中,我们重点关注0~3级。

注意:不是所有内核消息都会显示在控制台。内核有一个console_loglevel参数,只有级别低于该值的消息才会打印到终端。默认值通常是4(KERN_WARNING),所以调试信息(7级)默认是看不到的。想看到全部日志,可以临时调整:

echo 8 > /proc/sys/kernel/printk

3.4 常见内核错误解读

这部分我结合实战经验来讲。下面这些错误,你在dmesg里大概率都见过。

3.4.1 硬件相关错误

# 磁盘I/O错误
[12345.678901] sd 0:0:0:0: [sda] Unhandled error code
[12345.678902] sd 0:0:0:0: [sda] Result: hostbyte=DID_OK driverbyte=DRIVER_OK
[12345.678903] sd 0:0:0:0: [sda] CDB: Read(10): 28 00 00 00 00 00 00 00 08 00
[12345.678904] end_request: I/O error, dev sda, sector 0

看到这种错误,基本可以断定磁盘有坏道或物理故障。我建议你立刻用smartctl检查硬盘健康状态,别犹豫。

# 内存错误
[12345.678901] EDAC MC0: CE error on CPU#0Channel#0_DIMM#0
[12345.678902] EDAC MC0: CE error on CPU#0Channel#0_DIMM#0

内存错误分两种:CE(可纠正错误)和UE(不可纠正错误)。CE出现少量几次问题不大,但如果频繁出现,说明内存条快不行了。我曾经遇到一台服务器每周报几次CE,没当回事,结果三个月后直接宕机——UE来了。

3.4.2 驱动加载失败

[12345.678901] nvidia: module verification failed: signature and/or required key missing
[12345.678902] nvidia: disagrees about version of symbol module_layout

这种错误通常是因为内核版本和驱动版本不匹配。我建议你检查一下:

  • 驱动是否针对当前内核编译
  • Secure Boot是否开启(会导致签名验证失败)
  • 内核API是否发生变化

3.4.3 文件系统错误

[12345.678901] EXT4-fs error (device sda1): ext4_find_entry:1436: inode #12345: comm ls: reading directory lblock 0
[12345.678902] Aborting journal on device sda1-8.
[12345.678903] EXT4-fs (sda1): Remounting filesystem read-only

文件系统报错后,内核会自动将分区重新挂载为只读,防止数据进一步损坏。这时候别慌,先别重启,用fsck修复。我个人的经验是:先做磁盘镜像,再跑fsck,万一修坏了还有退路。

3.4.4 内核Panic

[12345.678901] Kernel panic - not syncing: Fatal exception
[12345.678902] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.10.0-8-amd64
[12345.678903] Hardware name: Dell Inc. PowerEdge R740/0F3X7P, BIOS 2.12.0 06/09/2021
[12345.678904] Call Trace:
[12345.678905]  dump_stack+0x6d/0x8b
[12345.678906]  panic+0x101/0x2e0
[12345.678907]  do_exit+0x7d/0xb0
[12345.678908]  oops_end+0x5a/0x60
[12345.678909]  no_context+0x1a1/0x1b0
[12345.678910]  __bad_area_nosemaphore+0x1a1/0x1b0

内核Panic是最严重的错误,系统直接挂掉。关键信息在Call Trace里,它告诉你崩溃的调用链。我一般会关注:

  • 哪个函数触发了panic
  • 哪个驱动或模块在调用链上
  • 硬件信息(Dell R740说明是物理机)

我的排查套路:

  1. 先看Call Trace顶部的函数名,搜一下是不是已知bug
  2. 检查最近是否更新了内核或驱动
  3. 如果是硬件相关,检查内存、CPU、磁盘
  4. 收集完整日志,提交给厂商或社区

3.5 知识体系总览

下面这张图把本章的核心逻辑串起来了。你一看就明白:dmesg只是入口,真正要理解的是缓冲区机制、日志级别和错误解读。

内核日志分析知识体系 dmesg 命令 环形缓冲区 固定大小,循环覆盖 内存中,掉电即失 O(1)写入,性能开销小 8个日志级别 0 EMERG → 7 DEBUG console_loglevel控制输出 dmesg -l 按级别过滤 常见错误解读 硬件错误(磁盘/内存) 驱动加载失败 文件系统错误 内核Panic 核心:dmesg → 缓冲区 → 级别 → 错误定位

3.6 实战建议

最后给你几个我自己的习惯,希望能帮你少走弯路:

  • 养成习惯:每次系统启动后,先跑dmesg -l err看一眼。别等出问题了再查。
  • 日志持久化:配置rsyslog把内核日志写到文件,避免缓冲区被覆盖后丢失信息。
  • 关注Call Trace:内核报错时,Call Trace比错误描述更有价值。学会看调用链,能快速定位问题模块。
  • 不要盲目重启:遇到内核错误,先收集dmesg日志再重启。重启后缓冲区就清空了,想查都查不到。