
1. 初识Kdump与vmcore内核崩溃的黑匣子当服务器突然宕机时最让人头疼的莫过于找不到崩溃原因。这就好比飞机失事后找不到黑匣子让人无从查起。Kdump就是Linux内核的黑匣子记录仪它能在系统崩溃时自动保存内存快照vmcore而crash工具则是我们解读这个黑匣子的解码器。我处理过不少线上崩溃案例发现很多运维同学面对vmcore文件时常常手足无措。其实只要掌握几个关键命令就能像侦探破案一样从内存快照中找出系统崩溃的蛛丝马迹。典型的分析场景包括内核Oops信息定位死锁问题排查内存泄漏分析硬件故障诊断准备分析环境需要三个关键文件crash工具通过yum/apt直接安装vmcore文件通常位于/var/crash目录带调试信息的内核镜像建议从发行版官网下载kernel-debuginfo包# 安装crash工具CentOS示例 yum install crash -y # 下载调试符号包 debuginfo-install kernel-$(uname -r)2. 启动分析进入crash的侦探模式第一次打开vmcore时那种感觉就像侦探初次勘察案发现场。执行以下命令即可进入分析环境crash /usr/lib/debug/lib/modules/$(uname -r)/vmlinux /var/crash/xxx/vmcore成功加载后你会看到类似这样的现场信息KERNEL: /boot/vmlinux-3.10.0-1160.el7.x86_64 DUMPFILE: /var/crash/127.0.0.1-2023-07-15-14:22:33/vmcore CPUS: 8 DATE: Sat Jul 15 14:22:33 2023 UPTIME: 18:45:21 LOAD AVERAGE: 0.52, 0.58, 0.59 TASKS: 687 NODENAME: web-server-01 PANIC: BUG: unable to handle kernel NULL pointer dereference at 0000000000000050这里特别要注意PANIC行它直接告诉我们内核遇到了空指针解引用错误。但具体是哪个模块、哪行代码导致的还需要深入调查。3. 基础侦查五大核心命令实战3.1 bt命令回溯犯罪现场btbacktrace是我的第一个必用命令它能显示崩溃时的调用栈。就像查看监控录像的回放功能让我们看到崩溃前内核的执行路径。crash bt PID: 16824 TASK: ffff88003d8a8000 CPU: 5 COMMAND: nginx #0 [ffff88003d8a7c58] crash_kexec at ffffffff810e27e2 #1 [ffff88003d8a7d28] panic at ffffffff81689948 #2 [ffff88003d8a7d50] oops_end at ffffffff81689948 #3 [ffff88003d8a7d78] no_context at ffffffff816793f1 #4 [ffff88003d8a7dc8] __bad_area_nosemaphore at ffffffff81679487 #5 [ffff88003d8a7e10] bad_area_nosemaphore at ffffffff816795f1 #6 [ffff88003d8a7e20] __do_page_fault at ffffffff8168c6ce #7 [ffff88003d8a7e80] do_page_fault at ffffffff8168c863 #8 [ffff88003d8a7ea8] page_fault at ffffffff81688b48 [exception RIP: nginx_http_handler0x150] RIP: ffffffffc0762150 RSP: ffff88003d8a7f58 RFLAGS: 00010246关键线索在RIP寄存器值ffffffffc0762150它指向导致崩溃的指令地址。注意最后的nginx_http_handler0x150说明问题出在nginx内核模块。3.2 dis命令反汇编凶器代码有了地址线索后用dis命令反汇编相关代码crash dis -l nginx_http_handler0x150 5 0xffffffffc0762150 nginx_http_handler336: mov 0x50(%rbx),%rax 0xffffffffc0762154 nginx_http_handler340: test %rax,%rax 0xffffffffc0762157 nginx_http_handler343: je 0xffffffffc07621a0 0xffffffffc0762159 nginx_http_handler345: mov (%rax),%rdx 0xffffffffc076215c nginx_http_handler348: mov %rdx,0x18(%rsp)这里清楚显示崩溃发生在mov 0x50(%rbx),%rax指令试图从RBX寄存器0x50的位置读取数据但RBX此时为NULL。这就是典型的空指针解引用问题。3.3 log命令查看系统日志log命令相当于查看案发现场的监控日志crash log | tail -20 [ 3452.671234] nginx: module verification failed: signature and/or required key missing - tainting kernel [ 3452.671345] nginx: loading out-of-tree module taints kernel. [ 3452.671456] nginx: module license Proprietary taints kernel. [ 3452.671567] BUG: unable to handle kernel NULL pointer dereference at 0000000000000050 [ 3452.671678] IP: [ffffffffc0762150] nginx_http_handler0x150/0x320 [nginx] [ 3452.671789] PGD 3d8a80067 PUD 3d8a81067 PMD 0 [ 3452.671900] Oops: 0000 [#1] SMP [ 3452.672011] Modules linked in: nginx(OE) vhost_net vhost tap...日志验证了我们的发现还显示nginx模块是未经签名的第三方模块taints kernel这往往是稳定性问题的根源。3.4 ps命令排查涉案进程ps命令可以查看崩溃时的进程状态crash ps | grep nginx 16824 16823 5 ffff88003d8a8000 RU 0.3 120384 24576 nginx 16825 16824 3 ffff88003d8a9000 RU 0.2 119872 20480 nginx 16826 16824 7 ffff88003d8aa000 RU 0.2 119872 20480 nginx带RU状态的进程是崩溃时的活跃进程。结合之前的分析可以确定是nginx工作进程16824号触发了内核崩溃。3.5 struct命令查看数据结构最后用struct命令检查相关数据结构crash struct nginx_http_ctx ffff88003d8a8000 struct nginx_http_ctx { req 0x0, resp 0xffff88003d8a8120, backend 0xffff88003d8a8200, ... }这里req指针为NULL而崩溃代码正尝试访问req-header_len偏移0x50处完美印证了我们的推断。4. 高级侦查内存与模块分析4.1 kmem命令检查内存健康当怀疑内存问题时kmem是首选工具crash kmem -i PAGES TOTAL PERCENTAGE TOTAL MEM 511276 2 GB FREE 506631 1.9 GB 99% of TOTAL MEM USED 4645 18.1 MB 0% of TOTAL MEM SLAB 1930 7.5 MB 0% of TOTAL MEM重点关注SLAB内存使用情况异常增长可能预示内存泄漏crash kmem -s CACHE OBJSIZE ALLOCATED TOTAL SLABS SSIZE kmalloc-8192 8192 128 256 32 32k kmalloc-4096 4096 512 1024 64 16k nginx_ctx_cache 256 2048 2048 32 8k -- 异常增长4.2 mod命令检查内核模块对于模块相关的问题mod命令必不可少crash mod ffffffffc0762000 nginx 12740 /var/lib/nginx/nginx.ko ffffffffc07a8000 faulty 8765 /lib/modules/faulty.ko特别注意标记为(OE)的模块表示它们是Out-of-tree模块稳定性风险较高。4.3 files命令查看打开文件当怀疑文件描述符泄漏时crash files 16824 PID: 16824 COMMAND: nginx ROOT: / CWD: /var/log/nginx FD FILE DENTRY INODE TYPE PATH 0 ffff88003d8a7000 ffff88003d8a7120 ffff88003d8a7240 CHR /dev/null 1 ffff88003d8a7000 ffff88003d8a7120 ffff88003d8a7240 CHR /dev/null 2 ffff88003d8a7000 ffff88003d8a7120 ffff88003d8a7240 CHR /dev/null 3 ffff88003d8a8000 ffff88003d8a8120 ffff88003d8a8240 SOCK 4 ffff88003d8a9000 ffff88003d8a9120 ffff88003d8a9240 REG /var/log/nginx/access.log ... 1023 ffff88003d8af000 ffff88003d8af120 ffff88003d8af240 REG /var/lib/nginx/cache.data5. 实战案例OOM杀手事件分析最近遇到一个典型案例服务器频繁重启vmcore显示是被OOM Killer终止。用以下命令组合快速定位crash log | grep -i oom [ 6852.123456] Out of memory: Kill process 18921 (java) score 789 or sacrifice child crash ps 18921 PID: 18921 TASK: ffff88003d8b0000 CPU: 3 COMMAND: java %MEM: 78.9 VSZ: 32168472 RSS: 25321472 crash kmem -i PAGES TOTAL PERCENTAGE TOTAL MEM 511276 2 GB FREE 1024 4 MB 0% of TOTAL MEM USED 510252 1.99 GB 99% of TOTAL MEM结合vm命令查看进程内存使用细节crash vm 18921 PID: 18921 TASK: ffff88003d8b0000 COMMAND: java MM PGD RSS TOTAL_VM ffff88003d8b1000 ffff88003d8b2000 25321472 32168472 VMA START END FLAGS FILE ffff88003d8b3000 00400000 01400000 8001875 ffff88003d8b4000 01400000 01c00000 8000871 /usr/lib/jvm/java-11-openjdk/lib/server/classes.jsa ...最终发现是Java进程内存泄漏导致。通过这几个命令的组合使用不到10分钟就定位到了根本原因。