Linux故障排查
Core Dump(程序)
Core Dump简介
当程序运行的过程中异常终止或崩溃,操作系统会将程序当时的内存状态记录下来,保存在一个文件中,这种行为就叫做Core Dump(中文有的翻译成“核心转储”)。我们可以认为 core dump 是“内存快照”,但实际上,除了内存信息之外,还有些关键的程序运行状态也会同时 dump 下来,例如寄存器信息(包括程序指针、栈指针等)、内存管理信息、其他处理器和操作系统状态和信息。core dump 对于编程人员诊断和调试程序是非常有帮助的,因为对于有些程序错误是很难重现的,例如指针异常,而 core dump 文件可以再现程序出错时的情景。
Core Dump相关配置ulimit
如果没有进行core dump 的相关设置,默认是不开启的。可以通过ulimit -c
查看是否开启。如果输出为0
,则没有开启,需要执行ulimit -c unlimited
开启core dump功能。
-
/proc/sys/kernel/core_uses_pid
可以控制core文件的文件名中是否添加pid作为扩展。文件内容为1,表示添加pid作为扩展名,生成的 core文件格式为core.xxxx;为0则表示生成的core文件同一命名为core。 -
/proc/sys/kernel/core_pattern
可以控制core文件保存位置和文件名格式。
# 开启core dump
ulimit -c unlimited
# 加上PID
echo 1 > /proc/sys/kernel/core_uses_pid
# 配置路径
$ vim /etc/sysctl.conf
kernel.core_pattern = /var/log/core_%e_%p_%t
以下是参数列表
%p - insert pid into filename 添加pid
%u - insert current uid into filename 添加当前uid
%g - insert current gid into filename 添加当前gid
%s - insert signal that caused the coredump into the filename 添加导致产生core的信号
%t - insert UNIX time that the coredump occurred into filename 添加core文件生成时的unix时间
%h - insert hostname where the coredump happened into filename 添加主机名
%e - insert coredumping executable name into filename 添加命令名
Kdump(OS内核)
什么是 kexec
Kexec 是实现 kdump 机制的关键,它包括 2 个组成部分:
一是内核空间的系统调用 kexec_load,负责在生产内核(production kernel 或 first kernel)启动时将捕获内核(capture kernel 或 sencond kernel)加载到指定地址。
二是用户空间的工具 kexec-tools,他将捕获内核的地址传递给生产内核,从而在系统崩溃的时候能够找到捕获内核的地址并运行。
没有 kexec 就没有 kdump。先有 kexec 实现了在一个内核中可以启动另一个内核,才让 kdump 有了用武之地。kexec 原来的目的是为了节省 kernel 开发人员重启系统的时间,谁能想到这个“偷懒”的技术却孕育了最成功的内存转存机制呢?
什么是 kdump ?
Kdump 的概念出现在 2005 左右,是迄今为止最可靠的内核转存机制,已经被主要的 linux™ 厂商选用。kdump 是一种先进的基于 kexec 的内核崩溃转储机制。当系统崩溃时,kdump 使用 kexec 启动到第二个内核。第二个内核通常叫做捕获内核,以很小内存启动以捕获转储镜像。第一个内核保留了内存的一部分给第二内核启动用。由于 kdump 利用 kexec 启动捕获内核,绕过了 BIOS,所以第一个内核的内存得以保留。这是内核崩溃转储的本质。
kdump 需要两个不同目的的内核,生产内核和捕获内核。生产内核是捕获内核服务的对像。捕获内核会在生产内核崩溃时启动起来,与相应的 ramdisk 一起组建一个微环境,用以对生产内核下的内存进行收集和转存。
工作流程
启用Kdump
- Kdump 用到的各种工具都在 kexec-tools 中。
$ sudo apt-get install kdump-tools -y
$ dpkg -l |grep kexec
ii kexec-tools 1:2.0.14-1 amd64 tools to support fast kexec reboots
- 配置内核参数crashkernel
vi /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="net.ifnames=0 biosdevname=0 console=tty0 console=ttyS0,115200\
cgroup.memory=nokmem swapaccount=1 cgroup_enable=memory crashkernel=512M"
- 配置kdump参数
$ cat /etc/default/kdump-tools |grep -v "#"
USE_KDUMP=1
KDUMP_KERNEL=/var/lib/kdump/vmlinuz
KDUMP_INITRD=/var/lib/kdump/initrd.img
KDUMP_COREDIR="/var/crash"
KDUMP_COREDIR="/var/crash"
KDUMP_NUM_DUMPS=10
MAKEDUMP_ARGS="-c -d 31 --dump-dmesg"
KDUMP_CMDLINE_APPEND="irqpoll nr_cpus=1 nousb systemd.unit=kdump-tools.service ata_piix.prefer_ms_hyperv=0 default_hugepagesz=2M hugepagesz=2M hugepages=0"
kdump-config
$ sudo kdump-config
Usage: /usr/sbin/kdump-config {help|test|show|status|load|unload|savecore|propagate|symlinks kernel-version}
$ sudo kdump-config unload
$ sudo kdump-config load
$ sudo kdump-config show
DUMP_MODE: kdump
USE_KDUMP: 1
KDUMP_SYSCTL: kernel.panic_on_oops=1
KDUMP_COREDIR: /var/crash
crashkernel addr: 0x15000000
/var/lib/kdump/vmlinuz: symbolic link to /boot/vmlinuz-4.9.65
kdump initrd:
/var/lib/kdump/initrd.img: symbolic link to /var/lib/kdump/initrd.img-4.9.65
current state: ready to kdump
kexec command:
/sbin/kexec -p --command-line="BOOT_IMAGE=/boot/vmlinuz-4.9.65 root=UUID=7abda93b-8447-423d-ac71-88ab41aa711a ro console=ttyS0,115200n8 console=ttyS1,115200n8 console=tty0 biosdevname=0 net.ifnames=0 net.ifnames=0 biosdevname=0 cgroup.memory=nokmem quiet cgroup_enable=memory irqpoll nr_cpus=1 nousb systemd.unit=kdump-tools.service ata_piix.prefer_ms_hyperv=0 default_hugepagesz=2M hugepagesz=2M hugepages=0" --initrd=/var/lib/kdump/initrd.img /var/lib/kdump/vmlinuz
$ sudo kdump-config status
current state : ready to kdump
分析crush
注意:kernel-debug-info一定要与内核版本相匹配
$ sudo less /var/crash/202012252138/dmesg.202012252138
# crash文件分析
$ sudo apt-get install crash
$ sudo crash xxx/vmlinux /var/crash/202012252138/dump.202012252138