redhat-kernel-kdump-crash

  1. Kdump工具

什么是Kdump?

Kdump是一个基于kexec的内核崩溃转储机制,当系统崩溃时,kdump使用kexec启动到第二个内核。地热个内核叫做捕获内核或者又叫“2nd
kernel”,它以很少的内存启动捕获内核,并捕获转储镜像。Kdump的概念是目前最可靠的内核转储技术,已被主要的linux厂商使用。(例如Red
Hat系列)

某天挂载了一个新硬盘后,我的centos7系统第二天就出现了崩溃现象,报错如题“failed
to start crash recovery kernel arming”.

     
最近一直在搞redhat。之前客户的机器都没有配置kdump,于是挨个给几百台虚机配kdump。我顺便就研究了下kdump的相关东西。

  Kdump的工作机制是在内核崩溃时, 通过kexec 工具由BIOS启动一个备用内核,
由备用内核执行一系列任务,保存内存中崩溃内核的状态, 供后续故障分析用.

什么是Kexec?

Kexec是一种能够根据已经运行内核的上下文快速启动新内核的一种机制,而不经过BIOS。BIOS的启动在一些大型机器或者有大量外设的机器上时特别耗时。这种机制能够节省需要在不同内核之间切换的开发人员的时间。
Kexec在内核空间和用户空间都有对应的组件,内核提供了几个kexec重启功能的系统调用。用户空间的软件包”kexec-tools”使用这些系统调用,并执行加载和引导第二个内核(捕获内核)。
Kexec由两部分组成,一是内核空间的系统调用kexec_load,负责在生产内核(或者叫第一个内核)启动时将捕获内核(或者叫第二个内核)加载到指定的位置。而是用户空间的kexec-tools,它将捕获内核(second
kernel)的地址传递给生产内核(first
kernel),让系统在崩溃的时候能够找到捕获内核(second
kernel)的地址并运行。

意思大致为“内存崩溃捕获机制未能成功启动”,一搜才知道这是因为一个叫做kdump的服务无法启动导致的。

     
kdump是用来分析内核问题的好东西。当内核运行出现问题时,比如常见的死机,操作系统就已经不工作了。当计时器超时,也就是判断内核已经失效后,系统会引导crashkernel,也就是用来下载kdump的另一个内核。当它启动后,会按照kdump配置中的信息,将指定的内存空间中的内容存到硬盘指定位置。这样我们就可以根据生成的vmcore文件来分析是什么原因导致了系统故障。

  本文默认AMD或INTEL X86_64架构, RHEL7系统环境. 

Kdump怎么工作?

在当前系统发生崩溃时,新的捕获内核被加载,然后根据已设置的命令去将当前之前发生崩溃的系统的内存保存到一个特殊的文件(vmcore)中。

下面以Fedora26做为测试演示。(Fedora和CentOS系列的系统已经在kenrel中打开了CONFIG_KEXEC*选项。)

首先需要在系统启动时预留出给第二个内核运行的内存。内核参数”crashkernel=160M”会在系统启动时预留出160M内存的空间给捕获内核运行使用。”crashkerel=xM”还支持其他的参数,详细的可以参考内核参数文档
内核参数。

# dmesg | grep -i reserving
[    0.000000] Reserving 160MB of memory at 656MB for crashkernel (System RAM: 2047MB)

系统启动后我们可以从上面的命令中看到已经预留出了160M的内存从内存的656M处。

安装用户态的包”kexec-tools”,软件包中会提供kdump所需的服务和”kexec”快速内核启动命令,和压缩过滤内存的”makedumpfile”命令。

[root@localhost ~]# dnf install -y kexec-tools

配置,修改kdump相关的配置文件。

[root@localhost ~]# grep -v ^# /etc/kdump.conf 

path /var/crash
core_collector makedumpfile -l --message-level 1 -d 31


[root@localhost ~]# grep -v ^# /etc/sysconfig/kdump
KDUMP_KERNELVER=""

KDUMP_COMMANDLINE=""

KDUMP_COMMANDLINE_REMOVE="hugepages hugepagesz slub_debug quiet"

KDUMP_COMMANDLINE_APPEND="irqpoll nr_cpus=1 reset_devices cgroup_disable=memory mce=off numa=off udev.children-max=2 panic=10 rootflags=nofail acpi_no_memhotplug transparent_hugepage=never nokaslr"

KEXEC_ARGS=""

KDUMP_IMG="vmlinuz"

KDUMP_IMG_EXT=""

配置文件/etc/kdump.conf设置了kdump发生时vmcore文件的存储方式,此文件修改后需要重启kdump的服务。

配置文件/etc/sysconfig/kdump,如果只是修改了COMMANDLINE相关的参数,则不需要去重新build生成新的initramfs文件。

启动kdump服务:

[root@localhost ~]# systemctl restart kdump
[root@localhost ~]# systemctl status kdump
● kdump.service - Crash recovery kernel arming
   Loaded: loaded (/usr/lib/systemd/system/kdump.service; enabled; vendor preset: disabled)
   Active: active (exited) since Sat 2017-07-15 10:46:22 UTC; 36s ago
  Process: 2172 ExecStop=/usr/bin/kdumpctl stop (code=exited, status=0/SUCCESS)
  Process: 2180 ExecStart=/usr/bin/kdumpctl start (code=exited, status=0/SUCCESS)
 Main PID: 2180 (code=exited, status=0/SUCCESS)

Jul 15 10:46:21 localhost dracut[4264]: -rw-r--r--   1 root     root          127 Mar 28 02:15 usr/share/zoneinfo/Etc/UTC
Jul 15 10:46:21 localhost dracut[4264]: drwxr-xr-x   3 root     root            0 Jun 22 13:38 var
Jul 15 10:46:21 localhost dracut[4264]: lrwxrwxrwx   1 root     root           11 Jun 22 13:38 var/lock -> ../run/lock
Jul 15 10:46:21 localhost dracut[4264]: lrwxrwxrwx   1 root     root            6 Jun 22 13:38 var/run -> ../run
Jul 15 10:46:21 localhost dracut[4264]: drwxr-xr-x   2 root     root            0 Jun 22 13:38 var/tmp
Jul 15 10:46:21 localhost dracut[4264]: ========================================================================
Jul 15 10:46:21 localhost dracut[4264]: *** Creating initramfs image file '/boot/initramfs-4.11.9-300.fc26.x86_64kdump.img' done ***
Jul 15 10:46:22 localhost kdumpctl[2180]: kexec: loaded kdump kernel
Jul 15 10:46:22 localhost kdumpctl[2180]: Starting kdump: [OK]
Jul 15 10:46:22 localhost systemd[1]: Started Crash recovery kernel arming.

所有的服务都配置完成,如果此时系统发生了panic或者其他的一些导致系统崩溃的现象,这是kdump服务会将当时的内存镜像按照用户的配置保存起来。一个简单的方式是通过命令来触发:

[root@localhost ~]# echo c > /proc/sysrq-trigger

[some console log]
... ...
         Starting Kdump Vmcore Save Service...
kdump: dump target is /dev/vda1
kdump: saving to /sysroot//var/crash/127.0.0.1-2017-07-16-04:21:36/
[    2.718001] EXT4-fs (vda1): re-mounted. Opts: data=ordered
kdump: saving vmcore-dmesg.txt
kdump: saving vmcore-dmesg.txt complete
kdump: saving vmcore
Copying data                       : [100.0 %] -
kdump: saving vmcore complete
... ...
[/some console log]

当系统重启后就能在指定的目录下看到生成的vmcore文件。可以参考配置文件”/etc/kdump.conf”里的”path”字段。

[root@localhost ~]# ls -lt /var/crash/*/
total 33492
-rw-------. 1 root root 34253115 Jul 16 04:21 vmcore
-rw-r--r--. 1 root root    40360 Jul 16 04:21 vmcore-dmesg.txt

转储文件被保存后可以用”crash”这个软件包来分析这个”vmcore”文件。

开始提到了Kexec内核部分提供了一些系统调用,”kexec_load()” 和
“kexec_file_load()”,其中一个用来加载捕获内核 – “kexec
-l”,另外一个来提供系统重启 – “kexec -e”。

系统调用”kexec_load()”可以加载一个新的内核并之后能够被”reboot()”调用。它是被这样定义的:

long kexec_load(unsigned long entry, unsigned long nr_segments,
                       struct kexec_segment *segments, unsigned long flags);

其中一个比较重要的是”kexec_segment”结构体:

struct kexec_segment {
    void   *buf;        /* Buffer in user space */
    size_t  bufsz;      /* Buffer length in user space */
    void   *mem;        /* Physical address of kernel */
    size_t  memsz;      /* Physical address length */
};

当reboot()的参数为”LINUX_REBOOT_CMD_KEXEC”并被调用时,则启动新的内核时就调用”kexec_load()”系统调用。另外“CONFIG_KEXEC”必须在编译kernel时被打开。

系统调用”kexec_load_file()”会设置2个参数”kernel”和”initramfs”给”kexec”命令。”kexec”会读取这些数据来创建对应的数据段。

long kexec_file_load(int kernel_fd, int initrd_fd,
                           unsigned long cmdline_len, const char *cmdline,
                           unsigned long flags);

同样的”CONFIG_KEXEC_FILE”参数也要在内核编译时被打开。

redhat-kernel-kdump-crash。目前的大多数发行版都已经打开了”KEXEC”相关的配置参数。

以上就是一个kdump的简单流程。有关”kdump”能够捕获到的内核崩溃时间可以参考文档”/usr/share/doc/kexec-tools/kexec-kdump-howto.txt”。或者请参考我们写的测试用例
kdump-test。

参考资料:
kdump-paper
kdump-introduction
fedora-kexec-tools

那么什么是kdump呢?

     
kdump的配置可以直接redhat官网上去找,官方有提供配置的脚本,会自动备份你的配置并根据你的系统配置(主要是内存容量)修改对应配置文件里的参数。

1.1 内核管理工具Kdump安装

kdump 是一种先进的基于 kexec 的内核崩溃转储机制。当系统崩溃时,kdump
使用 kexec
启动到第二个内核。第二个内核通常叫做捕获内核,以很小内存启动以捕获转储镜像。第一个内核保留了内存的一部分给第二内核启动用。由于
kdump 利用 kexec 启动捕获内核,绕过了
BIOS,所以第一个内核的内存得以保留。这是内核崩溃转储的本质。详细的在:http://www.ibm.com/developerworks/cn/linux/l-cn-kdump1/index.html#major3

      其他的配置网上也都有,就不多说了。主要说几个点吧:

  Kdump是RHEL7中自带的内核管理工具.在RHEL7.1之前的版本,kdump作为安装完成之后的可选组件自动安装,从RHEL7.1开始kdump被植入安装界面,作为系统基础工具供安装选择.

那接下来查找失败的原因:

     
一个是/boot/grub/grub.conf里的crashkernel。crashkernel参数是指定给crashkernel留出多少内存空间的,你的内存越大,crashkernel在生成kdump时需要的内存越多,所以这个选项与内存大小有关,具体的需要去查一下,另外,redhat
5版本这个参数的写法是crashkernel=memory@offset的写法,但是在redhat
6中offset已经没有了,就是crashkernel=memory。

可以通过下面命令直接RPM包安装.

看到一个博文中说与启动文件配置有关

      第二个是/etc/kdump.conf中的core_collector makedumpfile -c
–message-level 1 -d
17。这条配置中-d是指定dumplevel,这里设置的是17,你可以根据redhat给出的说明修改为其他值。这个dumplevel会影响dump时dump内存哪些部分;尤其对于服务器来说,因为内存都非常大,如果全部页都dump的话,耗时长而且生成的vmcore非常的大,很占存储空间;通过指定不同的dumplevel,crashkernel会忽略一些没什么用的内存页,比如空白页,空白页里面没有数据,但是默认情况下它也会被dump下来。

yum -y install kexec-tools
rpm -q kexec-tools

查看/etc/grub.conf 文件,发现crashkernel=auto,

      第三个还是/etc/kdump.conf里的参数’default
reboot,这条很简单,但是很有用。不配置这条并不会影响kdump正常工作,但是kdump默认情况下是不会自动重启机器的,也就是说在kdump完成之后,就一直处在待机状态。而此时你通过显示屏看不出内核是正在dump或是已经dump完成,因为屏幕什么也不显示。为了保险起见你只能多等一会,等内核dump完成再手动重启。另外,如果服务器故障后做了dump,你又没有发现这件事,那服务器就一直处在不工作的状态,这样很可能影响使用这台服务器的人的正常工作。如果你装的是物理机,又不支持ipmi和kvm
console,机房又在别的地方。。。。。那不就坑爹了?你只有大老远跑一趟机房手动去按电源开关了。

同时,Kdump还配备了图形化管理工具,可以通过下面命令安装.

系统对crashkernel=auto的定义为:

      /etc/init.d/kdump
status,这条可以查看kdump的运行状态,当然如果是刚配置了kdump,必须要重启才能生效。

yum -y install system-config-kdump

如果系统的内存 <= 8 GB 对kdump
kernel不会保留任何内容;也就是说,crashkernel=auto 等

      echo c >
/proc/sysrq-trigger,这条是测试kdump的。记得输入这条命令之后系统内核会panic!!所以如果要测试需要在维护期间,不然业务都中断啦。成功的话,在你指定的目录下会生成vmcore文件(在新生成的文件夹里面),默认是/var/crash。

  对于RHEL7.4及之后的版本,kdump支持INTEL IOMMU.
而不支持RHEL7.3及之前的版本.

于关掉了机器上的kdump功能;

     
kdump生成成功了,那么怎么分析kdump呢?分析kdump需要下载相应的包才行。

1.2 通过命令行配置kdump内存容量

如果系统的内存> 8 GB但是<= 16
GB,crashkernel=auto会保留256M,等同于crashkernel=256M;

      需要的包中,kexec-tools在redhat
5以后都自带了,不用安装。另外两个是:

  kdump能监控系统内核运行状态,其地位比较特殊.
kdump的内存空间是在系统启动时,由引导程序分配的,相对于系统内核,kdump内存是一个独立的空间.

如果系统内存> 16GB, crashkernel=auto会保留512M,
等同于crashkernel=512M

      kernel-debuginfo-common-x86_64-2.6.32-xxx.el6.x86_64.rpm和

可以通过如下命令指定kdump的内存空间大小.

安装虚拟机时,给虚拟机设置的内存为1G,所以说系统关掉了kdump。

      kernel-debuginfo-2.6.32-xxx.el6.x86_64.rpm

crashkernel=128M     #为kdump保留128M的内存空间.

接下来就是改写配置,但是没能在系统中找到博文中所说的/etc/grub.conf这个文件,后来想到从Centos
7之后启动就采用grub2 了,所以vi
/etc/grub2.cfg把其中的crashkernel=auto改成crashkernel=256M重启就成功了。

     
xxx替换为相应的内核版本号就是要下载的包了注意这两个包在redhat的安装镜像中是没有的,yum源似乎也没有,需要自己到网上去下载。我是在

   crashkernel的值可以设置成“auto”,在一些拥有较大内存的系统中,利于实现Kdump的自动化管理.

     
注意这里的版本号,不是和你的内核版本对应,而是和vmcore的版本号对应。如果你是本机生成了vmcore,在本机上分析,那么不存在这个问题;如果是一台6.2的redhat生成了vmcore,你把它传到了redhat
6.5的机器上去分析,那么你应当在这台6.5上安装6.2版本的kernel-debuginfo-common和kernel-debuginfo。注意这两个包只能安装一个,也就是说不同版本的kernel-debuginfo-common(和kernel-debuginfo),只能在一台机器上安装一个,如果要分析不同版本的vmcore,只能先删除原先的包,再安装另一个版本了。

crashkernel=auto

      环境准备完成,接下来分析vmcore了。分析使用的是crash命令:

  当然,crashkernel的值还可以通过如下形式实现更灵活的配置.

crash /usr/lib/debug/lib/modules/2.6.32-xxx.el6.x86_64/vmlinux
/var/crash/xxx/vmcore

  crashkernel=<范围1>:<大小1>, <范围2>:<大小2>

     
两个参数,vmlinux路径和vmcore路径(如果你没安装前面的包,这个路径下是没有vmlinux的)。如果成功载入的话,就会进入crash的shell里面。

crashkernel=512M-2G:64M,2G-:128M    #当系统内存在512M-2G之间时,为Kdump保留64M的内存空间;当系统内存大于2G时,为Kdump保留128M的内存空间.

     crash>

  还可以这样:

      常用的命令就是:

crashkernel=128M@16M    #为Kdump保留128M的内存空间,内存地址从16M(physical address 0x01000000)开始.

crash> bt

crash> log

1.3 Kdump的存储

      bt是显示内核最后运行的命令相关的情况,log是内核的日志。

  Kdump的配置在/etc/kdump.cnf中.
kdump提供多种方式将捕获到内核崩溃数据本地保存或保存到远程主机.

     
其他命令网上搜一下就有了。或者在shell里面输入help也能看到有哪些命令。

#path /var/crash    #kdump本地存储目录,默认是存放在/var/crash目录下,可以根据使用习惯设置.
path /usr/local/cores 
...
#raw /dev/vg/lv_kdump    #kdump可以直接写入移动介质.
raw /dev/sdb1
...
#nfs my.server.com:/export/tmp    #kdump可以通过NFS保存到网络上其它存储设备中.
nfs test.example.com:/export/cores
...
#ssh user@my.server.com      #kdump可以通过SSH传输协议,保存远程主机上.
#sshkey /root/.ssh/kdump_id_rsa
ssh user@test.example.com
sshkey /root/.ssh/mykey

      这里给一个bt命令的输出吧:

  kdump.conf中还可以在 core_collector makedumpfile 选项后加上” -c “,
使kdump文件能够被压缩,以节省存储空间.

PID: 2511  TASK: ffff8808686a0b40  CPU: 8  COMMAND: “kondemand/8”

#0 [ffff88086a47d8a0] machine_kexec at ffffffff81031fcb

#1 [ffff88086a47d900] crash_kexec at ffffffff810b8f72

#2 [ffff88086a47d9d0] oops_end at ffffffff814f04b0

#3 [ffff88086a47da00] die at ffffffff8100f26b

#4 [ffff88086a47da30] do_trap at ffffffff814efda4

#5 [ffff88086a47da90] do_divide_error at ffffffff8100cfff

#6 [ffff88086a47db30] divide_error at ffffffff8100be7b

[exception RIP: find_busiest_group+1477]

RIP: ffffffff81054ad5  RSP: ffff88086a47dbe0  RFLAGS: 00010046

RAX: 0000000000000000  RBX: ffff88086a47ddfc  RCX: 0000000000000000

RDX: 0000000000000000  RSI: 0000000000000018  RDI: 0000000000000018

RBP: ffff88086a47dd70  R8: ffff88089c44f860  R9: 0000000000000000

R10: 0000000000000000  R11: 0000000000000001  R12: 00000000ffffff01

R13: 0000000000015fc0  R14: ffffffffffffffff  R15: 0000000000000000

ORIG_RAX: ffffffffffffffff  CS: 0010  SS: 0018

#7 [ffff88086a47dd78] thread_return at ffffffff814ecda1

#8 [ffff88086a47de38] worker_thread at ffffffff8108b33c

#9 [ffff88086a47dee8] kthread at ffffffff81090886

#10 [ffff88086a47df48] kernel_thread at ffffffff8100c14a

core_collector makedumpfile -c

systemctl start kdump.service    #启动Kdump服务
systemctl enable kdump.service    #使Kdump开机自启
systemctl is-active kdump       #检查Kdump是否已启动
active
echo 1 > /proc/sys/kernel/sysrq   #模拟内核崩溃,检查/var/crash/是否自动保存Kdump捕获的内核崩溃数据, 以确定Kdump是否正常工作
echo c > /proc/sysrq-trigger

      顶部显示的是进程的信息以及最后执行的命令。#数字就是堆栈信息。

  需要注意的是

     
至于更具体的分析。。。这个就没法讲了(我也不会)。vmcore里主要是堆栈信息之类的,基本上是内核开发人员才用crash来分析vmcore。对于其他人而言,也看不懂里面的内容,不过可以追踪以往的案例,通过vmcore的信息来判断是否是一个以前出现过的已知的BUG,从而根据以往的案例找到问题的原因并加以解决。

  (1)在RHEL7之前的版本中,kdump的存储目录会随着kdump服务的启动而由系统自动创建.
RHEL7中,如果改变了kdump的存储目录,则必须在启动kdump服务之前,手动创建kdump的存储目录,否则kdump服务会启动失败.

  (2)如果在安装界面禁用了kdump, 而安装完成之后再通过systemctl start
kdump启动kdump, 会报内存不足无法启动的错误.
kdump的内存空间是在内核加载之前由boot分配的, 所以必须修改boot.
最好使用kdump的图形管理工具 system-config-kdump 加载kdump的默认配置,
使kdump处于可用状态, 然后重启系统, systemctl status kdump
服务处于激活状态(active).

1.4 利用crash功能分析内核崩溃

  利用crash功能组件能够分析linux内核崩溃时的网络、磁盘、CPU、系统内核状态,快速定位故障点.

crash组件可以通过RPM包安装.

sudo yum -y install crash       #安装crash
sudo debuginfo-install kernel    #安装内核调试模块

 sudo crash /usr/lib/debug/lib/modules/<kernel>/vmlinux
/var/crash/<timestamp>/vmcore  #启动crash调试

测试一下:

图片 1

图片 2

crash基本调试命令:

crash>log    #崩溃时日志记录
crash>bt     #崩溃时的堆栈信息
crash>vm     #崩溃时的内存状态
crash>ps     #崩溃时的进程状态
crash>files   #崩溃时的打开的文件
crash>exit   #退出crash

2 linux内核调校

2.1 kernel的调校途径

  RHEL7中提供三种内核调校方法:

  (1)使用sysctl 命令;

  (2)修改/etc/sysctl.d/ 目录下的内核配置文件;

  (3)通过shell 在/proc/sys 目录下挂载虚拟文件系统;

2.2 sysctl命令可以列出、读取、设置内核参数,
还可以将参数设置为临时或永久.

sysctl -a        #列出所有可调校的项
sysctl kernel.version    #列出kernel的版本信息

sysctl <tunable class>.<tunable>=<value>       #使调校参数临时生效
sysctl -W <tunable class>.<tunable>=<value>   #使调校参数永久生效

2.3 修改/etc/sysctl.d/99-sysctl.conf 目录下的99-sysctl.conf文件

cp /etc/sysctl.d/99-sysctl.conf /etc/sysctl.d/99-sysctl.conf.bak    #备份系统默认的内核参数文件
vim /etc/sysctl.d/99-my.conf    #创建新的内核参数文件

...
<tunable class>.<tunable> = <value>   #写入要调校的参数类和值
 <tunable class>.<tunable> = <value>
...
save    #保存文件
reboot sysctl -p /etc/sysctl.d/99-my.conf  #重启系统或者使用sysctl -p 命令载入新的内核参数配置

2.4 sysctl 调校内核参数

(1)调整最大请求的aio数量.

sysctl -a | grep fs.aio    #查看内核默认的最大aio值
sysctl fs.aio-max-nr=2048576  #临时调整aio最大值

图片 3

(2)开启本地ipv4转发功能.

sysctl net.ipv4.ip_forward = 1

(3)设定进程能被分配到的最大内存空间.

sysctl vm.max_map_count = 65530

(4)设定系统中同时运行的最大进程数.

sysctl kernel.threads-max = 16161

  在root权限下,通过sysctl 命令的内核参数调校, 基本上能直接控制linux
的内核所有行为, 满足实际生产中的绝大多数需求.

  

网站地图xml地图