WEBKT

systemd 看门狗(WatchdogSec)机制在工业网关中的硬件级崩溃恢复实践与调参陷阱

5 0 0 0

工业网关通常部署在无人值守、电磁环境复杂的现场,进程死锁或总线挂起是常态而非异常。依赖人工重启不现实,而纯硬件看门狗又缺乏业务状态感知能力。systemd 的 WatchdogSec 恰好填补了这一空白:它将用户态应用的健康状态与底层 /dev/watchdog 硬件计时器打通,实现“业务无响应即自动复位”的闭环。但在实际落地中,参数配置稍有不慎,轻则频繁误重启,重则导致系统彻底变砖。本文将从机制原理出发,梳理工业场景下的调参逻辑与避坑指南。

机制拆解:从 sd_notify 到硬件复位

systemd 的看门狗并非魔法,其工作链路严格遵循 用户态 -> systemd -> 内核 -> 硬件 的路径:

  1. 服务启动时,若 Unit 文件中声明了 WatchdogSec=,systemd 会在后台启动一个计时器。
  2. 应用程序必须定期调用 sd_notify(0, "WATCHDOG=1") 向 systemd 发送心跳。
  3. systemd 收到心跳后,会通过 ioctl(WDIOC_KEEPALIVE) 刷新内核的 /dev/watchdog 设备节点。
  4. 若超时未收到心跳,systemd 停止喂狗,内核看门狗驱动触发硬件复位(或执行预设策略)。

关键在于:systemd 本身不直接操作硬件,而是作为代理层将用户态心跳映射为内核喂狗指令。 这意味着你的服务必须正确实现 Type=notify 并集成 libsystemd 或等效的心跳发送逻辑。

核心配置示例

以网关数据采集服务 data-collector.service 为例:

[Unit]
Description=Industrial Data Collector Service
After=network.target

[Service]
Type=notify
ExecStart=/usr/bin/data-collector --config /etc/gateway/collector.yaml
Restart=on-failure
RestartSec=3
# 业务容忍的最大无响应时间
WatchdogSec=30s
# 配合 RuntimeWatchdogSec 使用,确保系统级喂狗
RuntimeWatchdogSec=60s

[Install]
WantedBy=multi-user.target

代码端(C/C++)需在主循环或独立线程中定时发送:

#include <systemd/sd-daemon.h>
// 在主循环或定时器回调中
sd_notifyf(0, "WATCHDOG=1\nSTATUS=Processing batch %d", batch_id);

调参陷阱:为什么你的网关总在“假死”与“狂重启”间摇摆?

工业现场的血泪教训表明,90% 的看门狗问题源于对时序和边界的误判:

陷阱 1:WatchdogSec 设置过短,被正常阻塞操作误杀
网关常需执行同步 I/O(如读取慢速传感器、等待 Modbus 响应)。若 WatchdogSec=5s,而某次总线仲裁耗时 6s,systemd 会判定服务僵死并触发重启。
解法WatchdogSec 应 ≥ 最坏情况下的业务处理耗时 × 1.5。建议结合 sd_watchdog_enabled() 动态获取实际超时值,并在长耗时操作前主动发送 WATCHDOG=1

陷阱 2:混淆 WatchdogSecRuntimeWatchdogSec
WatchdogSec 仅针对当前 Unit 服务;RuntimeWatchdogSec 作用于整个系统运行期。若只配前者,服务崩溃后 systemd 虽会尝试重启服务,但底层硬件看门狗可能早已超时导致整机硬复位,打断 systemd 的优雅恢复流程。
解法RuntimeWatchdogSec 必须大于所有关键服务的 WatchdogSec 最大值,为 systemd 留出故障转移窗口。

陷阱 3:忽略 Type=notify 的初始化延迟
服务启动后若未立即发送 READY=1,systemd 会认为服务未就绪。此时即使业务正常运行,WatchdogSec 计时器也不会启动,导致后续心跳错位或 systemd 判定启动失败。
解法:确保资源初始化(数据库连接、网络绑定、硬件握手)完成后,再调用 sd_notify(0, "READY=1")

陷阱 4:内核看门狗驱动未正确加载或权限不足
部分定制内核未启用 CONFIG_WATCHDOG 或默认喂狗驱动(如 imx2_wdt, sp805_wdt)。systemd 启动时会静默失败,日志中仅显示 Failed to enable watchdog
解法:启动时检查 journalctl -u systemd --no-pager | grep watchdog,确认 Watchdog running 状态。必要时在 systemd.conf 中显式指定 RuntimeWatchdogSec= 强制启用。

验证与排错清单

部署前务必通过以下测试闭环:

  • 模拟僵死:kill -STOP <pid> 观察是否在 WatchdogSec 到期后触发复位。
  • 检查心跳链路:strace -p <pid> -e trace=write 查看是否向 /run/systemd/notify 写入 WATCHDOG=1
  • 验证硬件联动:拔掉喂狗线程,观察串口日志是否出现 watchdog: BUG: soft lockup 及最终硬件复位。
  • 边界压力:在高 CPU 负载下验证心跳是否因调度延迟丢失。

架构建议

对于高可用工业网关,不要将鸡蛋放在一个篮子里:

  1. 分级看门狗:核心控制进程用 WatchdogSec=15s,非关键采集进程用 30s,系统级 RuntimeWatchdogSec=45s
  2. 软复位优先:配合 Restart=always 让 systemd 先尝试拉起服务,硬件看门狗作为最后防线(兜底策略)。
  3. 状态持久化:看门狗触发前,确保关键数据已落盘或写入环形缓冲区,避免复位导致数据断层。

systemd 看门狗不是银弹,而是工程纪律的体现。精准的超时设定、严谨的心跳上报、以及对内核驱动链路的清晰认知,才是工业网关实现“真·无人值守”的基石。

系统可靠性工程师 systemd工业网关硬件看门狗

评论点评