找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2924

积分

0

好友

390

主题
发表于 4 天前 | 查看: 30| 回复: 0

背景说明

当服务器遇到 Linux 内核崩溃时,能否快速定位原因至关重要。目前,主流的 Linux 发行版默认都会开启 kdump.service 服务。它的工作原理是,在内核崩溃的瞬间,利用 kexec 机制快速拉起一个保留在内存中的第二个内核。这个“救援内核”会负责收集并转储崩溃时的日志信息,也就是我们常说的 vmcore 等文件。

这套机制需要服务器硬件的支持,好在如今常见的服务器基本都已具备此能力。在默认配置下,崩溃日志会以本地磁盘(disk)方式保存。对于 CentOS/Red Hat 系列的系统,默认保存路径是 /var/crash/

需要了解的是,默认生成的 vmcore 文件并非完整的内存镜像,为了节省磁盘空间和传输时间,makedumpfile 工具默认使用级别 31(-d 31),只导出内核态的数据。因此,vmcore 文件的大小主要取决于崩溃时内核占用的内存量,通常不会特别巨大。下面,我们就来详细介绍如何收集并初步分析这些 vmcore 文件。

获取 vmcore

当我们需要在主机上分析 vmcore 文件时,一个关键前提是安装对应内核版本的 debuginfo 包,以获取内核函数的符号信息。举例来说:

kernel-3.10.0-957.27.2.el7.x86_64            # 系统运行的内核版本
kernel-debuginfo-3.10.0-957.27.2.el7.x86_64  # 需要安装的对应 debuginfo 包

通常,我们有两种方式来快速分析 vmcore

  1. 在出问题的机器上直接安装对应版本的 debuginfo 包。
  2. vmcore 文件传输到另一台专门用于分析的主机。

无论哪种方式,分析主机都需要安装 crash 工具。第一种方式虽然快捷,但会改动线上服务器的环境,且不适合大规模部署。第二种方式传输需要时间,但非常适合对线上故障进行统一的汇总和深入分析,因此也是更常见的做法。

我们通常采用第二种方式。你可以修改 kdump 配置,使其通过 NFS 或 SSH 将崩溃日志直接传送到指定机器,也可以在问题主机重启后手动传送。这里要注意,传输速度会直接影响服务器恢复正常的时间,因为日志传送完成后,系统才会开始重启。

分析 vmcore

安装 debuginfo 包的核心目的是获取对应内核的符号文件(vmlinux)。因此,我们可以在专门的分析机上预先收集好业务所用各版本内核的 debuginfo 包和内核源码。建议的目录结构如下:

/data/
├── kernel-crash       # 存放从各主机收集来的 vmcore 文件
├── kernel-debuginfo   # 解压后的各版本 debuginfo 文件(包含 vmlinux)
├── kernel-package     # 存放下载的 kernel 及 debuginfo 的 rpm 包
└── kernel-source      # 对应线上内核版本的源码文件,便于查阅

你可以使用 rpm2cpio 命令来解压不同版本的 rpm 包,获取所需文件。操作示例如下:

mkdir /data/kernel-debuginfo-3.10.0-957.21.3
pushd /data/kernel-debuginfo-3.10.0-957.21.3
rpm2cpio /data/kernel-package/kernel-debuginfo-3.10.0-957.21.3.el7.src.rpm | cpio -div
popd

最终,kernel-debuginfokernel-source 目录下的结构可能如下:

/data/kernel-debuginfo/
├── kernel-debuginfo-2.6.32-642.13.1.el6.x86_64
├── kernel-debuginfo-3.10.0-862.14.4.el7.x86_64
├── kernel-debuginfo-3.10.0-957.21.3.el7.x86_64
└── kernel-debuginfo-3.10.0-957.27.2.el7.x86_64

/data/kernel-source/
├── linux-2.6.32-642.13.1.el6
├── linux-3.10.0-862.14.4.el7
├── linux-3.10.0-957.21.3.el7
├── linux-3.10.0-957.27.2.el7

准备工作就绪后,使用 crash 命令,并指定对应内核版本的 vmlinux 文件和收集到的 vmcore 文件,就可以开始分析了:

# crash /data/kernel-debuginfo/kernel-debuginfo-3.10.0-957.21.3.el7.x86_64/usr/lib/debug/lib/modules/3.10.0-957.21.3.el7.x86_64/vmlinux vmcore

crash 7.2.3-10.el7
......

      KERNEL: /export/kernel-debuginfo/kernel-debuginfo-3.10.0-957.21.3.el7.x86_64/usr/lib/debug/lib/modules/3.10.0-957.21.3.el7.x86_64/vmlinux
    DUMPFILE: vmcore  [PARTIAL DUMP]   # 注意此处提示为部分转储
        CPUS: 40
 ...
     RELEASE: 3.10.0-957.21.3.el7.x86_64
 ...
       PANIC: "BUG: unable to handle kernel NULL pointer dereference at           (null)"
         PID: 167966
     COMMAND: "java"
        TASK: ffff880103d74500  [THREAD_INFO: ffff880013c68000]
         CPU: 11
       STATE: TASK_RUNNING (PANIC)

crash> bt
PID: 167966  TASK: ffff880103d74500  CPU: 11  COMMAND: "java"
 #0 [ffff880013c6ba38] machine_kexec at ffffffff81051beb
 #1 [ffff880013c6ba98] crash_kexec at ffffffff810f2782
 #2 [ffff880013c6bb68] oops_end at ffffffff8163ea48
 #3 [ffff880013c6bb90] no_context at ffffffff8162eb28
 #4 [ffff880013c6bbe0] __bad_area_nosemaphore at ffffffff8162ebbe
 #5 [ffff880013c6bc28] bad_area_nosemaphore at ffffffff8162ed28
 #6 [ffff880013c6bc38] __do_page_fault at ffffffff8164184e
 #7 [ffff880013c6bc98] do_page_fault at ffffffff816419e3
 #8 [ffff880013c6bcc0] page_fault at ffffffff8163dc48
    [exception RIP: unknown or invalid address]
    RIP: 0000000000000000  RSP: ffff880013c6bd78  RFLAGS: 00010282
    RAX: ffff880103d74500  RBX: ffff880013c6be10  RCX: ffff880013c6bfd8
    RDX: 0000000000000000  RSI: 0000000000000000  RDI: ffff880103d74500
    RBP: 0000000000000000   R8: ffff880013c68000   R9: 0000000000000018
    R10: 0000000000000000  R11: 0000000000000001  R12: 0000000000000001
    R13: 00007f7e88012454  R14: ffffc9001ce8efc0  R15: ffff880013c6bd60
    ORIG_RAX: ffffffffffffffff  CS: 0010  SS: 0018
......
crash>

通过 bt(backtrace)命令,我们可以看到内核崩溃时的调用栈。上例清晰地显示了一个由 Java 进程引发的空指针解引用(NULL pointer dereference)错误。要掌握更多的调试命令和技巧,可以参考 crash 官方文档

分析 vmcore 的目的

内核崩溃时,会将内核缓冲区(kernel buffer)的信息写入 vmcore-dmesg.txt 文件,但缺乏符号信息通常让我们难以深究。而 vmcore 文件虽然提供了汇编和代码级别的信息,但它也只是部分转储,分析结果不一定能揭示全貌。通常需要结合这两个文件一起查看。

然而在实际运维中,分析 vmcore 存在一定局限性。很多时候我们难以 pinpoint 问题的根本原因,即便找到了,也可能因为稳定性、兼容性等原因无法立即升级内核。因此,对于每一次内核崩溃,我们分析 vmcore 的主要目的可以归纳为以下几点:

  1. 初步定因:明确内核崩溃的大致原因和类型(如空指针、内存越界等)。
  2. 深入挖掘:在时间允许的情况下,对崩溃原因进行更细致的代码级分析。
  3. 事件归类:将故障事件按照代码调用栈或错误类型进行分类和归档,积累知识库。
  4. 辅助外援:如果购买了原厂或第三方技术支持服务,提供详尽的 vmcore 分析结果能帮助他们更快定位问题。

线上处理注意事项

kdump 配置问题

如果内核崩溃的频率不高,可以保持 kdump 的默认配置,将日志存储在本地 /var/crash 目录:

# grep ^path /etc/kdump.conf
path /var/crash

如果崩溃发生频率较高,可以考虑配置 ssh 选项,将崩溃日志直接发送到内网指定的收集机器。这里要特别注意内网传输速度,速度越慢,文件传送耗时越长,机器恢复正常服务的时间也就越长。配置 ssh 时需注意以下几点:

# /etc/kdump.conf

path /var/crash
ssh kerenl-crash@collect-host
default dump_to_rootfs                                      # 如果 ssh 失败,则降级转储到本地磁盘
core_collector makedumpfile -l --message-level 1 -d 31 -F   # 启用 ssh 时需增加 -F 选项,使导出到远程的数据为 flattened 格式

启用 ssh 后,必须在 makedumpfile 命令中增加 -F 选项,数据会以 flattened 格式存储。如果 ssh 传输失败,则会以降级方式在本地存储为标准格式。远程收集主机收到的是以 .flat 为后缀的文件,可以通过 -R 选项将其转换回标准格式:

makedumpfile -R vmcore < vmcore.flat

快速查看原因

当需要快速了解崩溃原因以做出决策时,可以优先查看崩溃主机(如果已重启成功)生成的 vmcore-dmesg.txt 文件。这个文件包含了内核崩溃时的堆栈信息,能帮助我们快速把握问题轮廓。该文件通常位于如下路径:

/var/crash/127.0.0.1-2019-11-11-08:40:08/vmcore-dmesg.txt

加快 vmcore 分析

vmcore 文件的大小由 kdump 的转储级别(默认为 31,仅内核态数据)决定,通常小于系统 Slab 内存占用量(可通过 /proc/meminfo 查看)。为了加快分析速度,如果传输较慢,可以考虑将 vmcore 文件拉到内网预置好的分析机上。这台分析机需要提前准备好各版本内核的 debuginfo 文件,无需通过 rpm 安装,用 rpm2cpio 解压存放到指定目录即可。

备注:使用 crash 分析 vmcore 时,常会看到 [PARTIAL DUMP] 提示,这正表明了当前分析的是部分转储的数据,是正常现象。

处理反馈及建议

在分析内核崩溃时,建议遵循以下流程,以便快速向业务方反馈:

  1. 快速响应:首先查看 vmcore-dmesg.txt,了解故障大致原因。
  2. 经验复用:如果曾处理过类似问题,直接参考既有知识库方案。
  3. 深入分析:如果是新问题,则需分析 vmcore,并在约定时间内给出初步处理建议。
  4. 知识沉淀:反馈后,再对根本原因和处理方式进行深入分析,并汇总到知识库中。

处理复杂的系统级故障是提升运维团队能力的绝佳途径。如果你在分析 Linux 内核崩溃或其它运维难题时有独到心得,欢迎到 云栈社区 分享你的经验,与更多同行交流探讨。




上一篇:ARM平台exfat挂载oops:内核模块版本不匹配问题的深度诊断
下一篇:ARM64平台Linux内核调试实战:三种方法精确定位空指针Oops错误
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-4-7 17:07 , Processed in 0.803330 second(s), 43 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表