资讯动态

别再调大watchdog_thresh!Linux soft lockup排查实战

发布时间:2026/10/8 15:56:16 来源:尧图企业网站定制
最近又有人抱着同样的困惑来找我一台服务器反复报soft lockup日志里清清楚楚写着watchdog: BUG: soft lockup - CPU#3 stuck for 22s!。他一看网上有人说“调大 watchdog_thresh 就行”于是去/proc/sys/kernel/watchdog_thresh把默认值改成了 30甚至改成 60。日志确实安静了可业务该卡还是卡数据库连接超时、接口响应忽高忽低一个都没少。他问了一个很典型的问题“报警没了问题是不是就没了”这个问题的答案很多老运维心里都清楚报警没了恰恰说明问题还在只是内核看门狗机制选择了“闭嘴”。这篇文章就把这层窗户纸捅破说说 soft lockup 到底是怎么检测的watchdog_thresh动了之后发生了什么以及真正该怎么排查。如果你正被这种“日志刷屏、业务却还苟着”的问题折磨建议耐心看完至少能帮你把“调参掩盖”和“修根因”这两件事分清楚。1. 先搞明白soft lockup 到底在“锁”什么1.1 看门狗线程、时间戳和 tick三者怎么配合Linux 内核的看门狗机制说白了就是给每个 CPU 配了一个“值班保安”。每个 CPU 上都有一个内核线程名字叫watchdog/0、watchdog/1这种调度优先级很高用的是实时调度策略。它的日常工作非常枯燥定期往一个时间戳变量里写“我还在运行”。同时内核还有一个高精度定时器或时钟中断在后台盯着这个时间戳。如果在watchdog_thresh设置的这个秒数内某个 CPU 上的watchdog/X线程压根没机会运行时间戳一直没更新看门狗定时器就会认为“这个 CPU 已经失去了正常调度的能力”于是打出soft lockup的日志。关键点在于这个watchdog/X线程优先级极高它都跑不了说明 CPU 上一定有比它更“霸道”的事情占着。这种事通常不是普通用户态进程能干出来的而是内核态代码、中断处理、或者极端调度异常。所以看到soft lockup消息第一反应应该是“CPU 上发生了内核级的调度停滞”而不是“系统负载高”这么简单。另外需要知道soft lockup报出来的栈往往只是检测时刻的现场快照。那个打日志的进程可能是随便一个正巧在 CPU 上跑的任务并不一定是造成锁死的元凶。很多新人在这里被误导顺着栈去查一个无关进程查了半天毫无收获就是这个原因。1.2 soft lockup 和 hard lockup 不是一回事这里必须把两个概念拆开soft lockupCPU 仍然能响应中断但调度器长期切换不出新任务导致高优先级 watchdog 线程无法运行。hard lockupCPU 连时钟中断都处理不了通常是中断被长时间关闭或硬件异常只能用 NMI不可屏蔽中断才能探到。两者共用同一个watchdog_thresh阈值但检测路径完全不同。hard lockup依靠 NMI watchdogsoft lockup依靠普通内核线程和定时器。排障时如果只看到 soft lockup可以顺手确认一下nmi_watchdog是否打开否则你甚至会漏掉更深层的 hard lockup 风险。下面这个表可以帮你快速区分指标soft lockuphard lockup中断是否还响应一般还能响应中断被关基本不响应检测手段watchdog 内核线程 定时器NMI 处理器典型原因关抢占、自旋锁、长中断处理、虚拟化 tick 延迟关中断死循环、硬件故障、极端驱动 bug日志关键字watchdog: BUG: soft lockupNMI watchdog: BUG: hard lockup很多人在调大watchdog_thresh的时候根本没意识到自己同时调慢了 soft 和 hard 两张“报警网”。这会让某些硬件级的严重问题也被延期暴露后面的风险不是简单一句“日志少了”能抵消的。1.3 哪些情况最容易反复触发 soft lockup根据我这些年处理过的现场反复报 soft lockup 的场景大致能归成这几类驱动代码里长时间持有自旋锁或者中断处理函数里跑了大量逻辑。存储卡、网卡驱动出这种问题最频繁。内核模块在原子上下文里死循环。比如错误使用spin_lock后忘了spin_unlock或者在一个已经关闭抢占的代码路径里阻塞等待。CPU 进入过深的 C-state 深度睡眠或者 SMI系统管理中断频繁打断导致本地时钟 tick 不稳定。虚拟机环境里宿主机 CPU 超卖、热迁移、抢占导致 guest 的 vCPU 被暂停很久guest 内看来就是“CPU 卡了几十秒”。内核版本自身有 bug比如调度器、RCU、内存回收在某些极端路径下异常。这些原因的处理方式完全不一样。比如 C-state 导致的问题调大阈值有可能让日志消失但如果是驱动自旋锁问题调大阈值就是给故障埋雷。所以不要一上来就改参数先判断属于哪种类型。2. 调大 watchdog_thresh看起来有效其实只是把闹钟调傻了2.1 这个 sysctl 参数到底改了哪里kernel.watchdog_thresh的单位是秒直接写入/proc/sys/kernel/watchdog_thresh即可临时生效。也可以用sysctl -w kernel.watchdog_thresh30想持久化就写到/etc/sysctl.conf。它影响的不只是“日志打印频率”而是看门狗判定的时间阈值对 soft lockup 来说如果 watchdog 线程超过watchdog_thresh都没更新时间戳才会判定为异常。对 hard lockup 来说NMI 检测同样会参考这个阈值来判定中断停滞时间。举个例子。某 CPU 被一个中断处理函数牢牢占住 30 秒假设默认阈值是 10那么大约在第 11 秒或第 20 秒时就会触发报警如果你把阈值调到 60这个 CPU 就算卡了 30 秒看门狗也认为“还没到判定线”于是日志就不打了。看到没有不是问题消失了是判定标准被你自己放宽了。有人可能会想那我调到 300 秒总会报警了吧确实但结果往往变成等它报警的时候业务已经崩了现场已经被破坏日志都未必抓全。看门狗的意义是让你在故障初期就介入而不是让故障演变成事故之后才给你发通知。2.2 为什么说这是“掩盖”而不是“解决”举一个非常生活化的类比一个人发烧 40 度你不去查感染源反而把体温计的报警上限调到 42 度。体温计确实不叫了但病人该烧还是烧。watchdog_thresh就是那个体温计的报警线它不是药物更不是手术刀。在真实运维中“调大阈值”带来的表面效果特别有迷惑性监控告警少了值班人员松了口气业务方反馈“好像没有之前那么频繁了”但这可能只是心理预期变化底层 CPU 停滞、锁冲突、中断堆积全都继续存在一旦故障后续扩大日志窗口也被你人为拓宽了连从什么时候开始变坏的都无法精确定位。我亲眼见过一个例子有人把watchdog_thresh调到 120以为是“优化”结果一台存储节点的驱动问题持续恶化从偶发几秒钟不可用慢慢变成几十秒不可用因为没有日志报警没人关注最后文件系统直接进入只读状态。复盘的时候才发现最初的 soft lockup 日志就是唯一的早warning结果被参数调没了。2.3 调大阈值还会带来哪些隐性代价除了“发现变晚”还有几个容易被忽略的代价第一panic_on_softlockup的联动会变迟钝。有些生产环境会配置kernel.softlockup_panic1希望一旦出现锁死就快速 panic 并触发 kdump。你把阈值调大等于把 panic 的时间点也延后了。故障影响面在几秒内就可能从单核扩展到整个系统多等一分钟恢复时间就多一小时。第二问题会被“上报升级”。业务在几秒到几十秒的时间窗口内无响应监控层面可能表现为 APDEX 暴跌、超时率上升、负载均衡摘流量。你去看监控发现各种指标异常却唯独看不到内核日志这时反而更难判断问题到底是从哪来的。第三团队对系统的信任感会下降。日志系统最重要的价值之一就是“说真话”。当你亲手把看门狗阈值调大后续再发生类似问题时同事会怀疑“是不是又是绕行参数掩盖了问题”这种隐形成本很难量化但每个老运维都懂。3. 一分钟判断这个 lockup 是“真死锁”还是“假阳性”3.1 看日志栈顶大部分时候能看出端倪soft lockup日志里的 Call Trace 不是随便看看就行。我会先看栈顶函数落在哪里栈顶是native_safe_halt、default_idle、cpuidle_enter这一类CPU 当时多半在空闲路径上这种情况往往是时钟中断丢失或虚拟化 tick 不准导致的“假阳性”。栈顶是某个驱动的spin_lock、read_lock、wait_event、mutex_lock相关符号那基本可以确认是内核代码路径里的锁问题或长期阻塞属于真异常。栈顶是函数名特别陌生的模块符号优先怀疑第三方驱动或 ko 模块。这种情况建议直接modinfo找模块版本再跟厂商确认已知 bug。另外可以留意日志里有没有RIP:行这一行会直接给出当时正在执行的指令地址对应的函数。多数时候这一行比 Call Trace 更能说明问题。3.2 用几个命令快速确认现场在决定是否调参之前我会先跑一遍下面的组合# 看当前阈值和看门狗开关 cat /proc/sys/kernel/watchdog_thresh cat /proc/sys/kernel/nmi_watchdog # 抓最近的内核日志找 lockup 前后的线索 dmesg -T | tail -300 # 看 CPU 负载和进程 pidstat -d -p ALL 1 top -b -n 1 # 看中断分布是否异常暴涨 cat /proc/interrupts # 看虚拟化 steal time确认是不是宿主抢占 vmstat 1 5这些命令跑完基本能判断出个大概方向。vmstat的st列如果持续很高说明 guest 的 vCPU 正在被宿主机“偷走”运行时间guest 内出现 soft lockup 可能就是误报警。但要注意对业务来说它并不“误”因为服务确实卡了只是根因不在 guest 内核而在宿主机资源分配或超卖策略。3.3 真死锁场景和误报场景的对照典型特征倾向判断调大阈值是否适合栈顶指向自旋锁/驱动函数且高负载触发真死锁 / 驱动 bug不适合必须查根因栈顶指向空闲函数频率与 CPU 深度睡眠吻合C-state / tick 丢失可临时缓解但最好关 C-statevmstat的st高且集中在大规模虚拟化平台宿主机抢占可临时缓解但打铁还需宿主硬固定在某一个 CPU 核上反复出现且与某设备中断相关中断风暴 / 驱动中断处理过长不适合必须查中断来源内核升级或驱动更换后消失已知内核 bug不需要调阈值说白了“调大阈值”只能挡住“假信号”挡不住“真损失”。如果判断方向偏了那调完这个参数最多是给自己多争取一点心理安慰后续该处理的问题一样都躲不掉。4. 实操如何一步一步定位根因而不是把阈值调大4.1 先把现场固定下来再谈“改不改”很多服务器在报 soft lockup 之后过几分钟又恢复正常等你去查的时候现场已经没了。所以我强调先做“现场固定”再做变更。我的建议顺序是把dmesg完整保存一份特别是 lockup 前的几十行日志。很多时候问题不是凭空出现而是前面已经有一堆中断、内存分配失败、驱动报错。记录内核版本和发行版uname -a如果切了 kABI 或加了补丁也要写清楚。确认看门狗相关的 sysctl 当前值包括kernel.watchdog_thresh、kernel.nmi_watchdog、kernel.softlockup_panic。检查上次修改参数的时间和对应的变更记录避免多人运维导致“参数都不知道谁改的”这类情况。如果环境允许还可以考虑内核自带的tracepoint或 ftrace 工具但那是高级玩法。一般先看日志和监控已经能定位七八成。4.2 几个真正有效的定位思路查中断风暴。阻塞 CPU 的元凶最常见的是中断处理函数。执行下面的命令多刷两次watch -n 1 -d cat /proc/interrupts | awk {print \$1, \$2, \$3, \$4}如果某个中断号在一个 CPU 上的增长速率远超其他 CPU而且时间点与 soft lockup 报警吻合那就重点查这个设备的中断处理逻辑。网卡多队列、NVMe 队列、RAID 卡中断都可能成为风暴源。查 C-state / SMI。服务器 CPU 为了省电会进入很深的 C-state。部分老平台在深 C-state 下本地 APIC timer 可能被拖延产生 soft lockup 误报。这种现象有个特点服务器负载很低的时候更容易出现高负载反而不出现。可以先看看当前 CPU 支持哪些 C-statecat /sys/devices/system/cpu/cpu*/cpuidle/state*/name如果确认是 C-state 导致的可以临时加内核参数intel_idle.max_cstate1或者关闭 BIOS 里的相关节能选项测试。这比调大 threshold 更接近根因虽然会牺牲一点功耗但换来稳定是值得的。查虚拟化 steal time。如果是虚拟机vmstat 1里的st列是关键指标。只要st经常超过 20%guest 里的时钟和调度就会明显失真。这时你想在 guest 内部“完全修复”并不现实更应该去看宿主机 CPU 是否超卖、是否在做热迁移以及宿主机上其他虚拟机是否有 CPU 争抢。配合 NMI watchdog 分辨深度问题。建议确认kernel.nmi_watchdog是开启状态sysctl -w kernel.nmi_watchdog1开启后如果问题升级为 hard lockup你会看到 NMI 日志证明中断关闭已经到了非常严重的程度。没有 NMI watchdog你可能连这一层都探测不到。4.3 真的走到“调阈值”这一步也请把规矩做全我不建议在生产环境“遇到 soft lockup 就调阈值”但如果经过前面判断确认是误报类问题并且短期无法替换硬件或升级虚拟化平台那么调阈值可以作为临时规避手段。这时至少做三件事在变更单里写明原因已知是 C-state 误报/虚拟化 tick 延迟临时调大阈值到 X根因待优化。把原值记录下来并设置一个提醒问题解决后要改回默认值。同时额外增加业务层监控比如接口耗时、CPU 软中断时间一旦出现异常还能从业务指标侧发现。这样做的好处是即使后来真的出了更大的故障别人看变更记录也能一眼明白这个参数是被故意放松的而不是无脑调出来的。5. 一个“调大阈值反而埋雷”的真实案例复盘5.1 现象与第一阶段的“快速处理”之前帮朋友看一台存储网关服务器现象是每天凌晨备份任务启动后某个固定 CPU 核会报soft lockup日志里指向一个存储驱动的自旋锁函数。当时的值班同事没有深究直接在/etc/sysctl.conf里加了kernel.watchdog_thresh60之后确实连续好几天没有日志报警。但他忽略了一个细节报警虽然没了备份任务每晚仍然会“卡”一段时间只是卡的时间被业务容忍了没有直接失败。这就像一台车在高速上每隔十分钟抖一下你把仪表盘的报警灯拆了但车还是在抖。5.2 后续恶化与最终定位三周后一次大流量备份任务触发了更严重的路径这次系统直接出现存储 IO 长时间不返回文件系统进入只读。复盘中发现最初的驱动自旋锁问题一直在悄悄恶化中断处理耗时从原来的几百毫秒涨到了数秒。由于watchdog_thresh被调到 60前几次真正的 CPU 停滞根本没有留下报警记录团队等于在一个没有“安全网”的状态下跑了几周。后来做的工作其实并不复杂升级存储驱动到修复版本问题消失把watchdog_thresh改回默认值所有类似机型统一检查固件版本避免同类问题再犯。如果当时不去调阈值而是直接更新驱动那几周的风险期完全可以缩短到一天。这个案例特别典型因为它说明了一个真相watchdog_thresh这个参数本身没有善恶但你在没找到根因前就动它等于主动摘掉了预警系统。5.3 另一个方向的案例虚拟化误报时调大有理但不够还有一个常见反例。某个虚拟化平台上的 guest 经常报 soft lockup日志频繁到影响监控。排查后发现宿主机 CPU 超卖严重guest 的 vCPU 经常被抢占几十秒。这种场景下guest 内调大watchdog_thresh是可以理解的因为 soft lockup 确实有“误报”成分。但正确做法是调整宿主机资源分配、减少超卖、设置 vCPU 的 pinning或者停止热迁移。只调 guest 参数等于告诉业务方“我们已经在处理了”实际处理的是内核日志不是业务卡顿。所以即便是误报我也依然建议把它当成“问题”而不是“噪声”。6. 关于 watchdog_thresh 的常见误解与高频提问6.1 FAQ 速查表问题解答把watchdog_thresh调成 0 会怎样相当于关闭检测不推荐。内核可能直接不触发看门狗报警。这个操作比调大阈值更危险等于彻底拆掉安全网。调大后需要重启吗写/proc/sys是即时生效的写/etc/sysctl.conf需要手动sysctl -p或者在下次重启后生效。为什么日志里写stuck for 22s可我设的是 10因为检测是周期性采样且日志打印时机有延迟实际报告时间会比阈值略大属于正常现象。调大watchdog_thresh会影响 hung task 检测吗不直接关联。hung task 检查的是长期处于 D 状态的进程有自己独立的超时参数两者不要混修。出现 soft lockup 一定要 panic 吗不一定。可以配合kernel.softlockup_panic1强制 panic否则只是输出日志。为什么我调大后日志少了但业务还是卡因为阈值只决定“何时报警”不改变 CPU 停滞时长。该卡多久还是卡多久。6.2 我的几条建议最后分享几条个人经验不一定适合所有场景但至少能帮你少走弯路日志里出现soft lockup先拍照、再处理。这行日志是唯一能在故障后还原现场的线索别急着清空。监控层面不要只看内核日志业务侧的超时率、接口响应时间、CPU 软中断占比都要看。有时候业务指标比内核日志更早报错。如果同一个问题在多个同型号服务器上反复出现优先考虑硬件、固件、驱动层面的共性问题而不是一台一台去调系统参数。7. 写在最后别把“止痛药”当“治疗方案”我自己处理过的 soft lockup 问题里真正靠调大watchdog_thresh解决的几乎没有。那些只是临时缓解了告警压力最终胜出的都是老老实实去看调用栈、找驱动版本、测中断分布、查虚拟化时钟最后把根因挖出来。如果你现在服务器也在反复报 soft lockup我的建议很简单不要急着把watchdog_thresh调大先按这篇文章里的思路把现场留好、把类别分清楚、把根因找到。只有当你确认它只是 C-state 误报或虚拟化 tick 延迟而硬件和平台暂时又无法立刻优化时才轮到“临时调参”出场。内核看门狗机制本质上是一个“保险丝”它烧断的时候虽然疼但至少让你知道电路出了问题。你把保险丝换粗整个系统也许能继续转但下一次出问题的时候可能就不只是烧一根保险丝的事了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑