systemd 通过 ExecStartPost、Type=notify 和 systemd-run 实现服务健康检查:前者执行启动后校验,后者依赖应用主动上报就绪状态,定时任务则用于周期性探测,并结合 Restart 策略增强容错。

systemd 本身不直接提供“健康检查”功能,但可以通过组合标准机制实现服务启动后的主动探活与响应。核心思路是:让服务启动后,由 systemd 触发一个独立的检查逻辑;若检查失败,则按需重启或告警。
用 ExecStartPost 执行启动后校验
在 .service 文件的 [Service] 段中,使用 ExecStartPost 定义一条命令,在主进程启动成功后立即运行。它只在 ExecStart 成功返回(即进程已 fork 或进入 ready 状态)后执行:
- 适合轻量级检查,比如验证端口是否监听、HTTP 接口返回 200、PID 文件是否存在等
- 命令失败不会导致服务整体启动失败(默认行为),但可配合 Restart=on-failure 或自定义逻辑触发恢复
- 示例:检查应用是否在 8080 端口响应
用 Type=notify 配合应用主动上报
当你的服务支持 sd_notify(3) 协议时,推荐设为 Type=notify。应用启动完成、完成初始化并真正就绪后,调用 sd_notify(0, "READY=1") 告知 systemd。systemd 会等待该信号才认为服务“启动成功”:
- 避免因启动脚本返回过早,而实际服务尚未监听或加载完毕的问题
- systemd 会记录从启动到就绪的实际耗时,便于诊断延迟
- 若超时未收到 READY(默认 90 秒,可通过 NotifyAccess 和 TimeoutStartSec 调整),systemd 将标记启动失败并按 Restart 策略处理
用 systemd-run 启动临时检查任务
对于需要周期性验证的场景,不建议把轮询逻辑塞进主服务单元。更合理的方式是单独定义一个 .timer + .service 组合:
- 写一个专用的 health-check.service,只做一次探测(如 curl、netstat、SQL 查询等)
- 配一个 health-check.timer,设置 OnUnitActiveSec=30s 实现每 30 秒检查一次
- 在 health-check.service 中用 Restart=on-failure + RestartSec=1,使检查失败时自动重试;再通过 ExecStartPre 或脚本逻辑决定是否触发主服务重启(例如运行 systemctl try-restart myapp.service)
结合 Restart 策略增强容错
无论用哪种检查方式,最终都要让失败能转化为动作。关键参数要配对使用:
- Restart=on-failure:仅在进程异常退出(非 0 状态、被信号终止)时重启;适用于 notify 或 ExecStartPost 显式 exit 1 的情况
- Restart=always:任何退出都重启,适合守护进程类服务,但需配合 StartLimit* 防止崩溃风暴
- StartLimitInterval=60s 和 StartLimitBurst=3:60 秒内最多重启 3 次,超出则进入 failed 状态并暂停,避免无限循环
- RestartSec=5:两次重启之间等待 5 秒,给依赖服务留出恢复时间


















