Linux 如何实现进程健康检查?

13次阅读

kill -0 $PID 是最轻量检查进程是否存活且可响应的方法,返回0表示存在并可响应,1表示不存在或权限不足,2表示PID格式错误。

Linux 如何实现进程健康检查?

进程是否存在且可响应?用 kill -0 最轻量

检查一个进程是否存活,最直接的方式不是看它有没有在 ps 里,而是尝试向它发一个不带信号的探测——kill -0 $PID。这个操作不会终止进程,仅由内核验证 PID 是否存在、当前用户是否有权限向其发送信号。

常见错误是用 ps aux | grep myapp,这容易误判:grep 进程自身会匹配上,或进程名被截断、有空格导致漏检;更糟的是,进程可能卡死但仍在进程表中。

  • kill -0 返回 0 表示进程存在且可响应(至少没被冻结或僵尸化)
  • 返回 1 表示进程不存在,或权限不足(如跨用户检查需 root)
  • 返回 2 表示 PID 格式错误或为负数(比如传了字符串

如何判断进程“活着但没干活”?加超时 + I/O 检查

仅靠 kill -0 不足以说明服务可用——进程可能卡在死锁、无限循环或阻塞 I/O 上。这时需要结合外部可观测性手段:

  • 对监听端口的服务,用 timeout 3 bash -c 'echo > /dev/tcp/127.0.0.1/8080' 2>/dev/NULL 测试 TCP 连通性(注意:需启用 bash/dev/tcp 支持)
  • 对提供 http 接口的服务,用 curl -f -s -o /dev/null --max-time 3 http://localhost:8080/health-f 确保非 2xx 响应也报错
  • 检查关键文件句柄是否异常增长:lsof -p $PID | wc -l,长期持续上涨可能是资源泄漏迹象

systemd 服务怎么写健康检查?用 ExecStartPreHealthCheck

如果你用 systemd 管理进程,别自己写轮询脚本。v240+ 的 systemd 原生支持 HealthCheck,但前提是服务声明为 Type=notifyType=exec 并配合 WatchdogSec=

更通用稳妥的做法是利用 ExecStartPre + 自定义检查脚本,或在服务启动后由外部探针驱动:

  • 在 unit 文件中加 Restart=on-failureRestartSec=5,让 systemd 在进程退出非零码时自动拉起
  • systemctl is-active --quiet myapp.service && systemctl is-failed --quiet myapp.service 组合判断“运行中且未失败”
  • 避免在 ExecStart 中嵌套复杂健康逻辑——这会让 systemd 无法准确识别主进程,导致 systemctl stop 失效

为什么不能只依赖 pspidof?它们不反映真实状态

pidof myapppgrep myapp 只查进程名匹配,而现代应用常以相同名字启动多个实例(比如多 worker),或改名(prctl(PR_SET_NAME)),甚至 fork 后主进程退出、子进程继续跑——这时 pidof 找不到主 PID,但服务仍可用。

更隐蔽的问题是僵尸进程(Z 状态):它还在进程表里,ps 能看到,但已不可交互,kill -0 会失败。这类进程必须由父进程 wait,否则只会越积越多。

真正可靠的健康检查永远要贴近业务语义:HTTP 服务看 /health 返回,数据库看能否执行 select 1,消息队列看能否 publish/consume。进程层只是第一道门,别让它成为唯一依据。

text=ZqhQzanResources