dmesg 是什么
dmesg(display message 或 driver message 的缩写)用来读取内核环形缓冲区(kernel ring buffer)中的日志。当 Linux 内核发现了什么事情,比如新硬件接进来了、磁盘有坏道了、网卡掉线重连了、内存出了 ECC(Error Correcting Code)错误了,都会往这个缓冲区里写一条记录。
我第一次真正重视 dmesg 是因为一次硬盘故障。那是深夜两点,监控告警说某台数据库服务器的 IO 延迟飙升。我登录上去看各种日志都没发现直接证据,直到想起 dmesg,跑了一看,内核已经连续报了好几个小时的 I/O error。一条 "Buffer I/O error on device sda" 让我锁定了坏盘。从那以后,dmesg 就成了我排查硬件问题时的第一站。
dmesg 基本用法
什么都不加直接跑:
# 直接查看内核日志
dmesg
这和 journalctl -k 看到的内容本质上是同一份数据。默认的输出内容很多,基本上一个系统从开机到现在的所有内核消息都在里面。最新的消息在最后面。输出量取决于系统运行时间,刚开机时可能几十行,跑了几天的服务器可能有几千甚至上万行。
如果你只想看最后几条(类似 tail):
# 只看最后 10 条内核消息
dmesg | tail -10
# 持续跟踪最新的内核消息
dmesg -w
-w 是我最常用的参数之一。比如你插入一个 U 盘,想确认内核是否识别了设备,先跑 dmesg -w,然后插上设备,控制台会实时打印出新消息:
[ +0.123456] usb 1-1: new high-speed USB device number 4 using ehci-pci
[ +0.045678] usb 1-1: New USB device found, idVendor=0781, idProduct=5581
[ +0.003456] usb-storage 1-1:1.0: USB Mass Storage device detected
[ +0.008901] sd 0:0:0:0: Attached SCSI removable disk sdb
同样是看设备热插拔,用 dmesg -w 比去翻 /var/log/messages 快多了。
按级别过滤:只看你想看的
dmesg 的每条消息都有日志级别,从高到低是 emerg、alert、crit、err、warning、notice、info、debug。过滤到关键信息:
# 只看错误和更高级别的日志
dmesg --level=err
# 同时查看错误和警告
dmesg --level=err,warning
# 只看内核告警
dmesg --level=alert,crit
# 组合使用:只看最近的错误
dmesg --level=err | tail -20
--level 参数可以指定多个级别,用逗号分隔。我排查问题时一般先用 --level=err 看看有没有显式的错误,如果没有就扩大到 --level=err,warning。注意不要一上来就 --level=debug,那个输出量太大,反而淹没了有效信息。
我自己有个检查服务器的习惯:登录一台不熟悉的机器时,先跑一遍 dmesg --level=err。很多时候你会发现在错误级别下,这台机器已经报了不少异常,只是平时没人注意到。比如 RAID 卡的 BBU(Backup Battery Unit,RAID卡缓存电池)没电了、内存 ECC 校验在持续报错,这些在 dmesg 里都看得清清楚楚。
配合 grep 排查硬件故障
grep 和 dmesg 是排查硬件问题的最佳搭档。这里列出几个常见场景:
# 检查磁盘 I/O 错误
dmesg --level=err | grep -i -E 'iowait|i/o|buffer i/o|failed|error'
# 检查内存错误(常见于 ECC 内存报错)
dmesg --level=err | grep -i -E 'memory|ecc|dimm|ce error|uncorrected'
# 检查网卡问题
dmesg --level=err | grep -i -E 'eth|network|link down|nic'
# 检查 USB 设备问题
dmesg --level=err,warning | grep -i usb
# 检查有无文件系统挂载失败
dmesg | grep -i 'mount'
我举个真实例子。有一次一台数据库服务器每隔一周就会自动重启,监控查到重启时没有人工操作,系统日志也看不出异常。后来我在 dmesg --level=err 里看到一条 "CE memory error on DIMM_A2",再去查服务器的硬件管理界面,确认是内存条坏了。换了内存后,问题再也没有出现。如果当时没有看 dmesg,可能还要花好几周去排查是不是系统软件的问题。
另外还要提一下,磁盘出现问题的时候 dmesg 通常会给出非常明确的提示:
# 查看磁盘相关错误,常见的有
# sd 0:0:0:0: [sda] Unhandled sense code
# Buffer I/O error on device sda1
# blk_update_request: I/O error, dev sda, sector 12345678
dmesg | grep -i 'sd[a-z]'
看到 "I/O error" 或者 "unhandled sense code" 基本可以确认磁盘硬件有问题了。这个时候别想着修,赶紧备份数据准备换盘。
⚠️ 安全提醒:dmesg 本身是只读操作,不需要 root 权限也能看大部分内容。但某些高版本 Linux 内核引入了 kernel.dmesg_restrict 安全机制(通过 sysctl 控制),开启后普通用户无法看 dmesg,需要 sudo。如果你的环境注重安全,不要为了图方便把这个限制关掉。
dmesg -T:显示人类时间戳
dmesg 默认的时间戳是从系统启动开始计算的相对时间,看起来像 [12345.678901]。这对人类来说很不友好,你很难知道这个 "12345" 秒对应的是几点几分:
# 加上 -T 参数,转换为人类可读的时间
dmesg -T
# 结合 grep 和 -T 一起用
dmesg -T --level=err
# 找出某个时间段的内核消息
dmesg -T | grep "Jan 15"
-T 会把 [12345.678901] 变成 [Thu Jan 15 14:32:05 2025] 这样的标准时间格式。这个参数在排查故障时极其重要,因为只有知道了事件发生的准确时间,才能和其他日志(应用日志、监控日志)做关联分析。
要注意的是,-T 依赖系统时钟的准确性。如果系统启动后手动改过系统时间或者 NTP(Network Time Protocol,网络时间协议)同步了时间,启动时间戳的换算可能会有偏差。不过对于大部分场景来说,偏差几秒甚至几分钟并不影响排错方向。
dmesg 和 journalctl 的配合
dmesg 和 journalctl -k 看的是同一份数据,但各有侧重:
# journalctl 也能看到内核日志,而且筛选能力更强
journalctl -k --since "1 hour ago"
# journalctl 可以按时间范围精确筛选
journalctl -k --since "2025-01-15 14:30:00" --until "2025-01-15 15:00:00"
# journalctl 可以按优先级筛选
journalctl -k -p err
# journalctl 可以把内核日志和系统服务日志联合分析
journalctl -k -u sshd.service
两者的核心区别在于:
- dmesg 读取的是当前内存中的环形缓冲区,重启后会丢失
- journalctl -k 如果配置了持久化日志,可以查到历史记录
所以我的使用习惯是:排查正在发生的实时问题,用 dmesg 加 -w 或者 --level;排查已经发生的历史问题,用 journalctl -k 加时间筛选。
还有一个实用技巧是看启动时内核的硬件检测信息:
# 查看刚开机时的内核消息,UEFI/BIOS 阶段的信息
dmesg | grep -i -E 'booting|kernel command line|BIOS|UEFI'
# 查看 CPU 相关信息,确认 CPU 特征是否全开
dmesg | grep -i cpu
# 查看内存大小检测是否正确
dmesg | grep -i memory
刚接手一台新服务器时,我都会用 dmesg 检查 CPU 是否工作在正确频率、内存是否全部识别、硬盘是否都找到了。这些都是最基础的硬件巡检,dmesg 是最快的方式。
dmesg 的局限
dmesg 很好用,但别过度依赖。它有几个限制要记住:
第一,内核环形缓冲区的大小是固定的(通常几十到几百 KB)。如果消息太多,旧的消息会被新的覆盖。这就是为什么长时间运行的服务器上 dmesg 只能看到最近几天的内核消息,之前的信息都丢失了。
第二,dmesg 只包含内核空间的日志,不包含用户态程序的日志。你的 nginx、MySQL、Java 应用写的日志,dmesg 里不会有。
第三,对于某些硬件错误,如果错误发生得太频繁,内核可能会限速(rate limit),导致 dmesg 里只显示一部分错误。这种情况可以看 journalctl -k 或者配置内核参数 kernel.printk_ratelimit 来调整。
总结
dmesg 是硬件故障排查的"第一现场"。当应用层的日志给不出答案时,回到 dmesg 看内核怎么说,往往能快速定位问题。把它和 journalctl -k 配合起来使用,一个负责实时监控和硬件诊断,一个负责历史查询和时间关联分析,基本上覆盖了系统底层的所有日志需求。