☰
OpenEuler服务器宕机定位:从现场证据到内核分析
2026/9/30 3:05:47 网站建设 项目流程

处理过几十台宕机服务器之后,我最深刻的感受是:OpenEuler服务器宕机定位流程,真正的瓶颈不在分析工具,而在宕机后你有没有把正确的信息留下来。电源灯亮着、风扇转着、远程死活连不上,进了机房按键盘也没反应——这种场景下,如果直接重启,你就把最有价值的第一现场抹掉了。这篇内容围绕“错误位置排查”展开,覆盖宕机性质判断、现场证据抢救、vmcore分析、内存/文件系统/硬件分路排查,最后用一个我实际处理过的NVMe IO挂死案例把整条链路串起来。适合刚接触服务器运维的工程师,也适合有经验但想系统梳理一遍宕机排查思路的人。

1. 先分清“死透了”还是“假死”:宕机性质决定排查方向

1.1 “死透了”和“假死”在运维上的本质区别

宕机不是单一故障,而是多种故障的共同结果。同一个“远程连不上”,可能是内核panic彻底停摆,也可能是某个进程把CPU占满导致系统假死,还可能是IO卡死让所有任务都在等待。它们对应的证据来源完全不同:panic靠vmcore和dmesg,lockup靠NMI和watchdog日志,IO hang靠块设备和文件系统日志,OOM靠内存监控。所以第一步不是打开日志乱翻,而是先回答一个问题:这台机器现在属于哪一类。

有一次我接到报障说“机器ping不通”,到现场发现iBMC能通、串口还在出字符,那就不是内核panic,而是用户态假死。最后追下去是数据库触发OOM后系统疯狂换页,swap写满导致SSH和网络服务全部卡住。如果当时按老思路直接硬重启,那一堆“Out of memory”日志就全丢了,根因永远查不出来。分清性质和假死,排查方向会完全不同。

1.2 五条现场测试快速判断宕机性质

机器还在现场、还没重启之前,按顺序做下面几件事,每一条都能帮你排除一批可能性。

第一,看键盘灯和面板状态。按Caps Lock或Num Lock,如果键盘灯有反应,说明CPU和中断基本还活着,至少不是彻底的hard lockup;如果完全没反应,大概率CPU已经卡死,或者内核把中断关掉了。服务器如果没有标准键盘接口,这一步可以跳过,但机房里有KVM时非常快。

第二,检查BMC/iBMC和串口SOL。管理口能ping通、SOL能登录,说明硬件平台还活着;如果SOL上还能看到内核输出,说明系统还没完全死。反之,管理口都进不去或者连BMC也失联,问题可能已经下探到主板/电源/CPU层面。

第三,尝试Magic SysRq。前提是系统里 /proc/sys/kernel/sysrq 非零,这一步要在平时就打开。真到宕机时,用键盘Alt+SysRq+功能键,或者通过串口发送BREAK序列,如果系统只是假死,串口上会出现内核任务列表或内存信息;如果发出去毫无反应,那内核调度器大概率已经不工作了。很多老运维靠这一招就能区分“能救”和“必须硬重启”。

第四,看网卡灯和BMC事件日志。网卡指示灯异常熄灭,或者iBMC里刚报过“system hung”“PCIe error”“CPU internal error”,这些事件本身就是硬件侧的错误位置线索。别小看BMC那几条记录,很多内存和CPU故障在messages里只字未提,却在BMC SEL里写得明明白白。

第五,有带外条件就触发一次NMI。x86服务器可以从BMC/iBMC发送NMI中断给内核,如果内核还响应中断,NMI会触发panic并落进kdump;如果触发后既没panic也没重启,CPU多半已经死锁,问题在硬件层。这一条非常实用,但要注意:触发NMI相当于主动制造一次panic,必须确认当前不在业务高峰期。

提示:SysRq和NMI在已经宕机的机器上基本不会造成额外破坏,但平时没事不要随便往 /proc/sysrq-trigger 里写 c 或 s,那是在主动制造崩溃。

1.3 判断结果怎么影响后续步骤

判断完性质,再决定翻哪个日志,效率会高很多。我把常见情况整理成一张表,方便现场对照:

现象特征判断倾向首要排查方向
控制台有panic堆栈,SysRq无响应内核panicvmcore、dmesg、内核模块
dmesg报soft lockup,部分CPU还能响应软锁watchdog配置、驱动、RT调度
NMI无响应,键盘灯失灵硬锁/硬件死锁BMC事件、CPU/主板、固件
日志有hung_task、IO error,BMC仍通IO hang块设备、文件系统、存储链路
SSH卡死但内核有响应,messages有oom-kill用户态OOM/假死内存、cgroup、swap

这张表不绝对,但能帮你决定先翻哪个目录,而不是把messages从头到尾看三遍。所谓“错误位置排查”,第一步就是圈定错误所在的大位置:是内核、是驱动、是文件系统、还是纯用户态。位置圈得越准,后面每一步都越省时间。

2. 重启之前必须抢救的现场证据:日志、串口与内核转储

2.1 日志持久化:定位的第一道防线

OpenEuler的日志体系是systemd-journald加rsyslog。journald如果不做持久化,重启之后只有当前启动的日志,宕机前那次启动的记录会直接消失。很多人在现场敲journalctl -b -1想看上一次启动的日志,结果提示“No journal files found”,那一刻的心情我太理解了。

所以新装机的OpenEuler,我第一件事就是改/etc/systemd/journald.conf,把Storage=persistent打开,确认/var/log/journal目录可写。这个操作不解决宕机,但它决定了宕机之后你手里还有几张底牌。磁盘空间够的话,还可以顺手设一下SystemMaxUse=4G,避免日志无限增长。这一步做得越早,等真正出事的时候越从容。

2.2 “第一现场”证据清单

宕机后的黄金抢救期,其实是系统还在通电、还没重启的这段时间。按优先级收集以下信息:

  • 控制台或串口的最后输出:如果屏幕还能显示,拍照或录屏,最后二三十行往往就是崩溃前的状态。串口若接在BMC SOL上,部分BMC会保留一段回显,记得回去翻缓存。
  • /var/log/messages:OpenEuler上最核心的文本日志,内核消息、服务启停、调度记录都会进来。优先看宕机时间点前后30分钟,重点搜 panic、oom、hung_task、Call Trace。
  • journald持久化日志:journalctl --since "03:00" --until "03:10" -p warning,先看warning以上级别,过滤掉大量无意义info。
  • /var/crash 和 /var/lib/systemd/coredump:前者是kdump落盘目录,后者是用户态coredump,有文件就意味着有完整的“案发现场”。
  • /proc/cmdline 和 /var/log/dmesg:确认启动参数里有没有crashkernel、console串口参数,以及硬件探测阶段有没有异常。
  • BMC SEL和IPMI事件:很多服务器宕机后会留下硬件事件,比如“CPU thermal trip”“PCIe error”“DIMM CE/UE”,这些是硬件错误位置最直接的证据。
信息源关键路径能回答什么问题
内核日志/var/log/messages、journalctl宕机时内核在做什么
崩溃转储/var/crash/*/vmcore内核panic的完整栈
用户态崩溃/var/lib/systemd/coredump哪个应用崩了、崩在哪
硬件事件BMC SEL、/var/log/mcelog内存/CPU/PCIe硬件错误
启动参数/proc/cmdlinekdump和串口有没有配置

2.3 kdump有没有配置,决定你能挖多深

kdump是Linux内核崩溃转储机制。内核panic时,系统会保留一块crashkernel内存给捕获内核,把崩溃瞬间的内存映像写到磁盘。没有vmcore,很多内核栈只能靠事后猜;有了vmcore,你可以直接用crash工具打开,看崩溃函数、调用栈、各CPU状态,几乎等于拿到了事故现场的高清录像。

检查是否配置,两条命令就够了:

grep -o crashkernel= /proc/cmdline systemctl status kdump

如果/proc/cmdline里没有crashkernel,或者kdump服务是inactive,那就要尽快补上。安装配置步�骤也不复杂:

  1. 安装组件:dnf install kexec-tools crash,同时确保debuginfo源里有对应内核的kernel-debuginfo包。
  2. 编辑/etc/default/grub,在GRUB_CMDLINE_LINUX里加crashkernel=512M。
  3. 重新生成grub配置:grub2-mkconfig -o /boot/grub2/grub.cfg。UEFI机器路径可能是/boot/efi/EFI/openEuler/grub.cfg,注意区分。
  4. 启动服务:systemctl enable --now kdump。
  5. 重启一次让crashkernel生效,然后回来看cat /proc/cmdline。

我见过很多机器配了kdump但从没真正触发过,所以我建议每隔半年做一次panic演练,在维护窗口里执行echo c > /proc/sysrq-trigger,确认/var/crash能正常生成vmcore,再恢复业务。没有这一步,真出问题时kdump可能因为路径权限、磁盘空间或镜像不对,压根落不了盘。

3. 内核崩溃的核心定位:从vmcore到崩溃函数与调用栈

3.1 用crash打开vmcore的完整流程

拿到vmcore之后,先确认两件事:故障机的内核版本和vmcore文件完整性。uname -r和ls -lh /var/crash/时间-主机名/vmcore,版本对不上,后面所有分析都是白做。

然后搭建分析环境。如果你有一台同架构的Linux机器,直接在那边装工具:

dnf install crash dnf install kernel-debuginfo-$(uname -r)

如果找不到debuginfo包,先确认debuginfo源已启用。拿到vmlinux和vmcore后,进入crash:

crash /usr/lib/debug/lib/modules/$(uname -r)/vmlinux /var/crash/2025-01-01-03:10/hostname/vmcore

如果默认路径找不到vmlinux,用find /usr/lib/debug -name vmlinux定位。进入crash之后,最常用的命令就几个:

  • bt:打印panic时的调用栈,这是定位崩溃函数的核心命令。
  • log:显示崩溃前的内核日志,相当于把dmesg缓冲整个拉出来。
  • ps:看当时的进程列表,谁在跑,谁被卡住。
  • sym:把内存地址转换成函数符号。
  • dis:反汇编指定地址,看具体指令。

作为定位流程,优先bt和log,这两个能回答“错误位置在哪个函数、哪个子系统”。

3.2 理解panic输出里的“错误位置”

典型的内核panic日志会有一行类似这样的内容:

RIP: 0010:ext4_do_update_inode+0x1e5/0x2a0 Call Trace: __jbd2_journal_commit_transaction+0x8f/0x1b0 ? kmem_cache_alloc+0x12/0x90 ...

RIP是CPU实际执行到崩溃点时的指令地址,ext4_do_update_inode+0x1e5/0x2a0意思是:崩溃在ext4_do_update_inode这个函数内部,整个函数大小0x2a0,崩溃点距离函数开头偏移0x1e5。Call Trace从下往上读,越往下越是调用者,越往上越接近崩溃现场。真正需要关注的是栈上没带“?”号的稳定调用链,带“?”的行只是栈上残留地址,不一定真的执行过。

不同panic消息对应的错误位置也不太一样,常见的几种:

  • Kernel panic - not syncing: Fatal exception:某个oops升级成了panic,通常是空指针或非法内存访问。
  • Kernel panic - not syncing: Out of memory and no killable processes:内核自己也分配不到内存,比用户态OOM严重得多。
  • Kernel panic - not syncing: Attempted to kill init!:init进程被杀死,systemd都撑不住了。
  • BUG: unable to handle kernel NULL pointer dereference at ...:最常见的空指针崩溃,后面跟的地址往往是0x0附近。

这些文字本身就在告诉你错误的大位置,配合RIP和调用栈,可以精确到函数级别。

3.3 没有vmcore怎么反推

没有配置kdump的情况下,就只能靠日志拼图:

  1. journalctl -b -1 -k看上一次启动的内核日志,重点找最后200条。
  2. 翻/var/log/messages里宕机时间点附近,先搜panic、oops、BUG、Call Trace、Out of memory、hung_task。
  3. 确认系统是否重启过,uptime和last reboot -x能反推宕机时刻。
  4. 检查有没有SysRq触发的痕迹,这类日志会写进dmesg缓冲。
  5. 如果只是用户态无响应但内核还活着,看登录日志、cron日志、服务状态,有时能发现是某个脚本或进程把内存/磁盘耗尽。

没有vmcore的反推,有点像拼图只给你最后几块。这也是我一再强调提前配置kdump的原因——它可能是你唯一能看到完整内核调用链的机会。

4. 按“错误位置”分路排查:内存、文件系统、硬件与驱动

4.1 内存错误:OOM与硬件位翻转是两个世界

OpenEuler上内存耗尽不一定会panic,更多时候是OOM killer把某个进程杀掉。日志关键行长这样:

Out of memory: Kill process 12345 (postgres) score 72 or sacrifice child Killed process 12345 (postgres), total-vm:10240000kB

这说明错误位置在应用层,是某个用户态进程把内存吃满了,而不是内核坏了。继续用dmesg | grep -i "out of memory"和journalctl -p err找,再配合cgroup的memory.events看是不是超了限额。

硬件内存错误则是另一回事。MCE(Machine Check Exception)是CPU发现硬件错误后的上报机制,日志会类似:

mce: [Hardware Error]: Machine check: Memory Error ... bank=1

这种错误的物理位置是内存条或CPU cache,必须用memtest86/memtester或者BIOS内存测试验证,同时看BMC SEL里的DIMM记录。技巧:内存很大的机器,日常记录一下edac模块的/sys/devices/system/edac/mc/mc0/ce_count,如果这个值在持续增长,说明有根内存条正在老化,应该趁着业务低峰期换掉,别等宕机后再查。

4.2 文件系统错误:XFS/ext4的“位置”链条

文件系统引发的宕机,日志关键词往往不是panic,而是:

EXT4-fs error (device sdb1): ext4_lookup: ...: inode #12345: ... XFS (dm-0): metadata I/O error in "xfs_trans_read_buf" at daddr 0x...

分析顺序应该是从下往上:块设备层错误、文件系统层错误、应用层无响应。错误位置越往下越偏向硬件,越往上越偏向文件系统逻辑。命令行排查按这个顺序来:

smartctl -H -d sat /dev/sda # 检查硬盘健康 smartctl -l error /dev/sda # 查看历史错误位置LBA multipath -ll # 如果用了multipath,看路径健康状态

如果磁盘SMART干净但文件系统报错,要查阵列卡日志,比如storcli的storcli /c0 show events。还有一个容易被忽略的点:块设备超时时间。如果存储响应很慢,内核默认的IO超时可能导致请求永久挂起,最终触发hung_task宕机。针对慢速存储,可以调/sys/block/sdX/device/timeout,让错误更快反馈到上层。

4.3 硬件/驱动:MCE、PCIe AER与第三方驱动

PCIe设备报错也经常导致宕机,尤其是严重级别为Fatal时。日志类似:

PCIe Bus Error: severity=Uncorrected (Fatal), reported by 0000:03:00.0

错误位置就在那个PCIe设备上,用lspci -vvs 03:00.0看设备详情,再结合是否新换过硬件或固件。这类问题经常出现在网卡、RAID卡、GPU上。

第三方驱动是另一个高频“错误位置”。最典型的场景是:新装网卡驱动或GPU驱动之后没几天就宕机。判断方法:

  • 崩溃栈里是否有驱动函数名,比如ixgbe_xmit_frame、i40e_clean_rx_irq、nvidia_drm_*。
  • 用lsmod和modinfo对比“最近变更窗口”内的模块。
  • 检查驱动版本和内核版本的兼容性。OpenEuler对内核模块管理比较严格,建议用dkms或官方RPM包安装,不要手动insmod一个来源不明的ko,出了问题连跟踪都难。

4.4 用户态与systemd视角的错误位置

宕机不全是内核问题。有时候是一个关键服务卡死,导致系统“假死”。看systemctl status有没有failed单元,systemd-analyze blame看启动时有哪些服务耗时异常,coredumpctl info可以查用户态应用崩溃时的调用栈。

如果崩溃在用户态,定位方式完全不同:用gdb加调试符号看core文件,而不是crash工具。还有一点,如果系统配置了自动重启,比如内核参数panic=10或systemd单元Restart=always,你看到的现象可能是“频繁重启”而不是“一次宕机”。这时候要抓重启周期的规律,比如每天凌晨四点都来一次,那大概率是定时任务或监控脚本触发的,而不是硬件故障。

5. 完整案例复盘:一次OpenEuler 22.03服务器半夜宕机的定位全程

5.1 现场现象与环境

某数据中心一台跑PostgreSQL的OpenEuler 22.03 LTS SP3服务器,内核版本5.10.0-136.12.0.0.11.oe2203sp3.x86_64,磁盘是两块NVMe SSD做的软RAID1。凌晨三点多,业务监控发现连接全部中断,BMC显示OS no response。值班同事没多想就强制重启,起来后业务恢复,但大家心里都没底,怕第二天再来一次。

5.2 排查链路还原

开机后我先做三件事。第一,看uptime和last reboot -x,确认宕机时刻在03:11左右。第二,用journald查上次启动的日志:

journalctl --since "03:00" --until "03:15" --priority=warning

结果很典型:

03:10:48 kernel: INFO: task kworker/u4:2 blocked for more than 120 seconds. 03:10:48 kernel: "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.

这说明系统已经进入hung_task状态。第三,往前翻到03:08附近,看到一连串:

03:08:11 kernel: blk_update_request: I/O error, dev nvme0n1, sector 80251140 op 0x1:(WRITE) 03:08:12 kernel: nvme0n1: I/O error

到这里基本可以确定:宕机不是内核代码bug,而是NVMe块设备IO错误把请求卡住,最终触发hung_task,系统失去响应。这台机器当时没有配置kdump,所以没有vmcore可分析,但也正因为根因在块设备层,日志链已经足够清楚。

接着用smartctl确认硬件状态:

smartctl -H /dev/nvme0n1 smartctl -a /dev/nvme0n1 | grep -E "Media_Errors|Critical_Warning"

SMART整体状态是FAILED,Media_Errors不为零。再查BMC SEL,同时间段有一条“PCIe Correctable Error”记录,位置指向PCIe总线。问题链路就完整了:NVMe盘介质错误导致写入IO长期阻塞,block层无法完成IO,hung_task触发,系统无响应。

5.3 复盘教训:这个案例里最容易忽略的三件事

第一,别只看最后一条hung_task。很多人一看到hung_task就以为是内核bug,其实它只是一个结果。真正的错误出现在更早的“I/O error”,必须把时间往前推,找到第一个报错,那才是错误位置。

第二,硬件问题不一定表现为MCE。NVMe设备出问题,日志里更多是blk_update_request和nvme驱动的报错,而不是MCE。所以排查硬件不能只搜“Machine Check”。

第三,OpenEuler上建议提前设置内核panic行为和kdump。比如在/etc/sysctl.conf里加:

kernel.hung_task_timeout_secs=300 kernel.panic=10

再配上kdump,这样即使出现严重IO挂死,系统也能在可控时间内触发panic落盘,拿到vmcore之后再深入分析,而不是只能靠smartctl事后猜。

第四,日常就要监控NVMe的critical_warning和media_errors。很多环境完全没有这种监控,反而要等宕机后才查。有了这些指标,盘坏之前就能预警。

5.4 这个案例还能怎么扩展

如果系统里跑的是关键应用,可以进一步优化IO路径。比如给内核加nvme_core.io_timeout=60,让单盘IO错误更快反馈到上层,而不是无限阻塞;同时用multipath或硬件RAID提供冗余。如果确认是盘本身坏,直接热插拔更换;如果是固件bug,更新NVMe固件后再观察。

这个案例的内核定位其实相对简单,因为根因在块设备层。真正难的是那些“kernel panic + vmcore”的场景,那种情况要在crash流程里花更多时间。如果把“错误位置”当成坐标去查,先从硬件、再查驱动、最后进入内核,绝大多数宕机都能在半小时内找到方向。

排查宕机这件事,做得越久越觉得:真正专业的做法,不是宕机后反应快,而是宕机前已经把路铺好。kdump、日志持久化、串口console、BMC事件上报,这几样加在一起,才是一套完整的OpenEuler服务器宕机定位流程。你提前十分钟做这些配置,可能省下宕机后的十个小时。下次再遇到服务器“死透了”,你会感谢当初那个愿意在维护窗口里多敲几条命令的自己。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询