Linux 系統內核崩潰分析處理簡介


Linux 系統內核崩潰分析處理簡介

12 Nov 2019 

背景說明

目前絕大多數的 Linux 發行版都會將 kdump.service 服務默認開啟, 以方便在內核崩潰的時候, 可以通過 kdump 服務提供的kexec 機制快速的啟用保留在內存中的第二個內核來收集並轉儲內核崩潰的日志信息(vmcore 等文件), 這種機制需要服務器硬件特性的支持, 不過現今常用的服務器系列均已支持.

如果沒有特別設置, 系統都采用默認的 kdump 服務配置, 崩潰的日志文件默認以 disk 方式保存在本地的磁盤目錄,Centos/Redhat 系列的系統主要保存在以下目錄:

/var/crash/

一般生成的 vmcore 文件僅僅是內核崩潰時的一部分信息, 如果全部導出對磁盤和時間都是很大的消耗, 默認情況下, dump 的級別為 31, 僅導出內核態的數據, 詳見 makedumpfile -d 選項. 這種情況下系統崩潰一般生成的 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 方式將生成的日志傳到指定的機器, 也可以在問題主機重啟后手動傳到指定的機器. 當然主機間通信的速度要足夠快, 崩潰日志傳送完成后才會開始重啟操作, 所以越慢就意味着機器正常重啟需要的時間越長, 相應的從內核崩潰到可以簡單的 crash 分析之間的時間間隔就越大.

分析 vmcore

安裝 debuginfo 包的目的在於獲取對應內核版本的符號信息(vmlinux 文件), 所以我們可以在指定機器中收集了業務運行的所有發行版內核對應的 debuginfo 包和內核源代碼文件(方便查看代碼), 如下所示:

/data/
├── kernel-crash       -- 收到的各主機的 vmcore 文件
├── kernel-debuginfo   -- 對應線上內核版本的 debuginfo 文件
├── kernel-package     -- 常用的 kernel 安裝包
└── 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-debuginfo 和 kernel-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 命令指定 vmcore 文件對應版本的 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> 

可以參考 crash-book 學習更多的調試技巧.

分析 vmcore 的目的

內核崩潰時會將 kernel buffer 中的信息寫到 vmcore-dmesg.txt 文件, 不過由於缺乏符號信息我們一般難以找到更細致的線索. 而 vmcore 文件僅導出了部分內核轉儲日志, 實際上也不一定准確, 不過可以提供匯編和代碼級的信息. 通常需要我們結合兩個文件共同查看. 不過在實際的使用中, 存在很大的局限性, 因為很多時候難以確定問題的具體原因, 即便確定了原因我們可能也難以升級內核, 如果沒有單獨維護補丁更新, 就無法使用 kpatch 等在線升級功能. 所以從這方面來看, 每次出現內核崩潰的時候, 我們分析 vmcore 的目的主要在於以下幾點:

1. 明白內核崩潰的大致原因;
2. 可以對內核崩潰的原因做更細致的分析;
3. 可以對故障事件做代碼級別的分類和匯總;
4. 方便第三方廠商(如果購買了服務)分析原因定位問題;

線上處理注意事項

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 選項可以將 flat 格式轉為標准格式, 如下所示:

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 參數 dump 級別決定, 默認為 31 僅導出內核態的數據. 這種級別下一般由崩潰時內核占用的內存決定. 可以查看 /proc/meminfo 的 Slab 信息查看內核態大概的數據, 通常情況下 vmcore 都會小於 slab 的值. vmcore 傳到指定的機器需要一定的時間, 如果傳輸較慢, 可以將 vmcore 文件拉倒對應內網機器進行分析. 該機器需要提前裝好對應內核版本的 debuginfo 包, 當然不用非要 rpm 安裝, 我們可以將 debuginfo 包通過 rpm2cpio 方式解壓出來單獨存放到指定的目錄.

備注: 使用 crash 工具分析 vmcore 文件的時候通常會出現 [PARTIAL DUMP] 的提示, 這種提示一般在設置 dump 級別的時候進行提示, 更多可以參考 bugzella-857111.

處理反饋及建議

在分析具體原因的時候我們可以遵循以下的規則盡快給業務人員反饋處理建議:

1. 快速查看 vmcore-dmesg 文件了解大概的故障原因;
2. 如果碰到過此類問題就參考知識庫的處理;
3. 如果沒有碰到過, 需要單獨分析 vmcore 日志, 在指定時間內反饋處理建議;
4. 反饋后再慢慢分析可能的原因和處理方式, 匯總成知識庫;

參考

kdump.service
how does kexec works
kdump
crash-analyze
crash-book-pdf

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM