systemd watchdog 监测服务心跳的配置方法
我第一次给常驻服务补心跳保护时,遇到的误区是:进程还在,就以为服务健康。实际上线程可能死锁、事件循环可能卡住,systemd 看到的 PID 却仍然存活。服务级 watchdog 的正确做法,是在 unit 中设置 WatchdogSec=,再由主进程完成关键工作后定期发送 WATCHDOG=1。一旦两次通知间隔超过阈值,systemd 会把服务判为 watchdog 失败;配合 Restart=on-watchdog,才形成“检测假死并恢复”的闭环。
本文依据的官方说明地址是 https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html 与 https://www.freedesktop.org/software/systemd/man/latest/sd_watchdog_enabled.html。先给结论:心跳建议按 systemd 下发超时时间的一半发送,并且只能在服务确实还能推进工作时发送,不能让一个无条件定时器替业务线程报平安。
WatchdogSec=30s表示管理器最多等待 30 秒,不代表服务会自动产生心跳。sd_watchdog_enabled()可读取WATCHDOG_USEC,程序按其一半间隔调用sd_notify(0, "WATCHDOG=1")。Restart=on-watchdog只针对 watchdog 失败重启;启动频率限制仍然有效。
先分清 unit、主进程和通知套接字的职责
WatchdogSec= 启用的是 systemd 与服务之间的协议。服务启动完成后,管理器开始计时,并通过环境变量 WATCHDOG_USEC 把微秒级超时值交给进程;WATCHDOG_PID 则用于限定预期发送者。主进程通过 systemd 的通知套接字发送 WATCHDOG=1,管理器收到后重置计时器。

这里最关键的根因判断是:watchdog 检测的不是“进程是否存在”,而是“服务是否仍能在期限内证明自己有进展”。因此,我会把心跳放在主事件循环完成一次健康检查、成功处理队列或刷新关键状态之后,而不是另起一个永远能醒来的线程盲目发送。后者会让业务线程已经卡死的服务继续显示健康。
unit 文件这样配置
下面是一份可作为起点的 unit。Type=notify 便于服务用 READY=1 明确报告初始化完成;真正启用 watchdog 的仍是 WatchdogSec=,不要把两者混为一谈。
# /etc/systemd/system/example.service
[Unit]
# 服务说明以及需要先完成的网络目标
Description=Example heartbeat service
After=network-online.target
[Service]
# 主进程会通过 sd_notify 报告 READY 和 WATCHDOG
Type=notify
ExecStart=/usr/local/bin/example-service
# 30 秒未收到心跳就判为 watchdog 失败
WatchdogSec=30s
# 只在 watchdog 失败时自动重启
Restart=on-watchdog
# 避免连续失败时立即形成快速重启风暴
RestartSec=5s
# 明确只接受主进程的通知
NotifyAccess=main
[Install]
# 随常规多用户目标启动
WantedBy=multi-user.target
超时后,服务会进入 failed 状态,systemd 默认使用 SIGABRT 终止它,也可通过 WatchdogSignal= 调整信号。随后是否重启由 Restart= 决定;如果只想覆盖 watchdog,on-watchdog 比宽泛的 on-failure 更容易解释。
主循环按下发时间的一半发送心跳
程序不要把 30 秒硬编码两遍。sd_watchdog_enabled() 会判断管理器是否要求当前进程发送心跳,并返回 WATCHDOG_USEC。以下 C 代码保留了最重要的契约:仅在一轮业务工作成功后发送心跳。
#include
#include
#include
int main(void) {
uint64_t watchdog_usec = 0;
/* 返回值大于 0 表示当前进程需要发送 watchdog 心跳。 */
int enabled = sd_watchdog_enabled(0, &watchdog_usec);
/* 初始化成功后报告 READY;失败分支应直接退出并让 systemd 记录结果。 */
sd_notify(0, "READY=1");
for (;;) {
/* 这里代表一轮真实业务工作;只有成功推进状态才允许报心跳。 */
int work_ok = do_one_round_of_work();
if (work_ok 0) {
/* 使用超时时间的一半,给调度抖动和短暂阻塞留下余量。 */
sd_notify(0, "WATCHDOG=1");
usleep(watchdog_usec / 2);
} else {
/* 未启用 watchdog 时也避免空转。 */
sleep(1);
}
}
}
真实项目中还应使用单调时钟安排下一次发送,避免每轮处理耗时叠加后逐渐漂移。如果业务工作可能持续很久,就把“仍有进展”的判断设计成可观测检查,而不是在工作开始前先报心跳。
重载后先检查属性,再看失败结果
修改 unit 后,我会先重载并读取 systemd 实际采用的属性,而不是只检查文件内容。
# 让 systemd 重新读取 unit,并启动最新配置
sudo systemctl daemon-reload
sudo systemctl restart example.service
# 查看 watchdog 是否生效,以及当前服务状态和最近一次心跳时间
systemctl show example.service \
-p ActiveState -p SubState -p Result \
-p WatchdogUSec -p WatchdogTimestampMonotonic
# 从本次启动开始查看服务日志和 watchdog 失败线索
journalctl -u example.service -b --no-pager
如果 WatchdogUSec=0,优先检查 unit 是否重载、配置是否落在 [Service] 段,以及当前启动的是否是同名模板实例。若超时后看到 Result=watchdog 但没有重启,再检查 Restart= 和启动限速。StartLimitIntervalSec=、StartLimitBurst= 会阻止持续故障无限重启,这是保护机制,不是 watchdog 失效。

两个最容易踩的边界
第一,设置 WatchdogSec= 而未显式配置 NotifyAccess= 时,systemd 会把通知访问范围隐式设为 main。如果由辅助进程发送心跳,它的通知可能不被接受;即使放宽到 NotifyAccess=all,短命辅助进程的通知归属也可能难以确认。更稳妥的设计仍是让主进程发送。
第二,WatchdogSec= 是服务级软件 watchdog;systemd-system.conf 中的 RuntimeWatchdogSec= 面向硬件 watchdog,用于监督系统管理器乃至整台机器。两者解决的问题不同,不要为了服务假死直接去改硬件 watchdog。
常见问题
只写 WatchdogSec,服务会自动发心跳吗?
不会。它只让 systemd 开始等待通知,服务仍需通过 sd_notify 或等价接口主动发送 WATCHDOG=1。
心跳间隔必须恰好是超时的一半吗?
一半是官方接口说明中的推荐值,目的是为调度延迟留余量。程序应读取 WATCHDOG_USEC 计算,而不是复制 unit 里的固定秒数。
为什么进程没退出,systemd 仍然重启了服务?
因为 watchdog 监测的是通知期限。主进程仍在但没有按时发送有效心跳时,systemd 会按 watchdog 失败处理并执行配置的重启策略。
Python configparser ExtendedInterpolation 组织分层配置
- 上一篇
- Python configparser ExtendedInterpolation 组织分层配置
- 下一篇
- View Transitions API 处理跨页面导航动画
-
- 文章 · linux | 13小时前 |
- Linux zram 写回如何在内存与磁盘间平衡
- 373浏览 收藏
-
- 文章 · linux | 15小时前 |
- Linux Landlock 怎样限制普通进程访问文件目录
- 151浏览 收藏
-
- 文章 · linux | 19小时前 |
- Linux dm-verity 如何校验只读根文件系统
- 190浏览 收藏
-
- 文章 · linux | 22小时前 | Linux BPF ring buffer BPF_MAP_TYPE_RINGBUF libbpf bpf_ringbuf_reserve
- Linux BPF ring buffer 怎样向用户态传递事件
- 348浏览 收藏
-
- 文章 · linux | 1天前 |
- Linux nftables 集合如何动态维护封禁地址
- 193浏览 收藏
-
- 文章 · linux | 1天前 | Linux · 性能监控 · Pressure Stall Information poll Linux PSI POLLPRI 资源压力
- Linux PSI 触发器如何在压力超过阈值时通知进程
- 331浏览 收藏
-
- 文章 · linux | 1天前 |
- systemd socket 的 Accept=yes 如何启动实例化服务
- 386浏览 收藏
-
- 文章 · linux | 1天前 | Linux · 最小权限 StateDirectory systemd 服务 systemd DynamicUser 动态用户
- systemd DynamicUser 如何运行无固定账号的服务
- 261浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 402次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 478次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 487次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 435次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 260次使用
-
- Linux vmstat 如何分辨内存抖动与磁盘等待:si、so、wa 与复测顺序
- 2026-08-30 501浏览
-
- Linux搭建vsftpdFTP服务器教程
- 2026-04-30 501浏览
-
- Shell脚本安装教程:.sh一键安装指南
- 2026-03-16 501浏览
-
- Linux清空文件内容的几种方法
- 2025-12-01 501浏览
-
- Linux命令行下载文件技巧
- 2025-11-23 501浏览
