Linux 服务进程假死的检测方式

3次阅读

最直接判断linux服务假死的方式是发送轻量级探测信号或请求看是否响应:先用kill -0检查进程存在性,再通过curl健康端点、查日志、观察资源占用(cpu≈0%、fd/socket卡高位)组合验证。

Linux 服务进程假死的检测方式

怎么判断一个 Linux 服务进程是不是假死

假死不是崩溃,也不是退出,而是进程还在 ps 里挂着、systemctl status 显示 active (running),但实际不响应请求、不写日志、不处理信号。最直接的判断方式是:发一个轻量级探测信号或请求,看它是否“有反应”。

推荐组合验证:

  • kill -0 <pid></pid> 检查进程是否存在且可被访问(不真发信号)——仅说明内核还认它活着
  • curl -m 3 http://localhost:8080/health 或类似健康端点(如果服务暴露了)
  • 检查最近日志:journalctl -u myservice --since "2 minutes ago" | tail -5,看有没有新输出
  • 观察资源占用:假死进程常表现为 CPU 接近 0%、RSS 不增长、但文件描述符或 socket 连接数卡在高位

systemd 服务下如何自动发现假死

systemd 本身不主动探测业务逻辑是否存活,只管进程是否在运行。要防假死,得靠 HealthCheck* 类配置或外部探活。

实操建议:

  • 优先启用服务内置健康检查(如 nginxstub_statusredisPINGgolang net/http 的 /health),再配合 systemctl show --Property=ExecMainPID 获取 PID 后做探测
  • 若服务无健康端点,可用 ss -tlnp | grep :port 看监听 socket 是否仍在 —— 假死后 socket 常被内核回收,但进程没退出
  • 避免依赖 RestartSec=5 直接重启:假死进程可能拒绝 SIGTERM,导致 systemd 最终发 SIGKILL,丢失现场信息
  • 设置 WatchdogSec=30s 并在服务代码中周期性调用 sd_notify("WATCHDOG=1")(需链接 libsystemd),这是 systemd 原生防假死机制

用 shell 脚本做简易假死巡检的坑

很多人写个 while 循环 + curl 就当监控用了,但容易误报或漏报。

常见翻车点:

  • curl 默认不校验 HTTP 状态码,curl http://.../health 返回 503 也认为成功 —— 必须加 -f 参数让非 2xx/3xx 触发失败
  • 没设超时:curl 卡住会拖垮整个脚本,必须加 -m 3(秒级)和 --connect-timeout 2
  • ps aux | grep myapp 判断进程存在?危险!grep 自身也会匹配上,应改用 pgrep -f "^/path/to/myapp"pidof myapp
  • 脚本跑在 crontab 里时,PATH 和环境变量和交互式 shell 不同,curlsystemctl 可能找不到 —— 显式写全路径,比如 /usr/bin/curl

strace 跟踪假死进程时的关键观察点

当你已经怀疑某个进程假死,又不想立刻杀掉它,strace 是最贴近真相的工具。

执行 strace -p <pid> -e trace=recvfrom,sendto,accept,read,write,poll,select,epoll_wait -s 64 -T</pid> 后重点关注:

  • 是否长期卡在 epoll_waitpoll 上(说明事件循环没推进)
  • 反复 recvfrom 返回 0(对端关闭连接但程序没处理 EOF
  • 大量 futex 调用且阻塞时间长(锁竞争或死锁)
  • 系统调用耗时异常高(如 read 耗时 >1s),可能是磁盘 I/O 卡住或网络挂起
  • 注意:不要在生产环境长时间运行 strace,它会让目标进程暂停,影响服务;单次抓 10–20 秒足够定位卡点

假死往往不是单一原因,而是资源泄漏 + 错误处理缺失 + 信号屏蔽叠加的结果。最麻烦的是那种“看起来一切正常”的假死:日志照打、CPU 有波动、连接数缓慢上涨——这时候得看线程和 fd 泄漏,别只盯着主进程状态。

text=ZqhQzanResources