GUIDE / 工程
多机 Agent 掉线排查手册:七步定位
相关:一个人怎么带一支 Agent 舰队:心跳、指纹与失败闭环 · AI 小团队怎么开周会才不浪费时间 · 任务舰队 · 私有化部署
「机器掉线了」通常不是一个原因,而是七种可能里的某一种。按顺序排查,比凭经验猜快得多。
一、先分清三种「掉线」
| 形态 | 现象 | 实际含义 |
|---|---|---|
| 假掉线 | 看板显示离线,但任务还在产出 | 心跳上报链路断了,机器本身没事 |
| 真掉线 | 进程没了,任务停在半路 | 进程崩溃 / 被系统杀掉 / 机器重启 |
| 半掉线 | 心跳正常,任务长期不动 | 进程活着但在空转、卡在等外部响应 |
三种形态的处理方式完全不同。先分型,再动手——否则你会在「重启一下」上浪费一整个下午。
二、七步排查
| # | 看什么 | 判定 |
|---|---|---|
| 1 | 心跳时间戳 | 超过 3 个上报周期 = 假掉线或真掉线,进第 2 步 |
| 2 | 身份指纹 | 指纹与名册不符 = 配置漂移或同名机器覆盖 |
| 3 | 任务队列深度 | 队列堆积且不消费 = 消费进程死了 |
| 4 | 版本漂移 | 心跳版本 ≠ 部署版本 = 升级没生效 |
| 5 | 网络出口 | 能 ping 通但拉不到依赖 = 出口被限或 DNS 挂了 |
| 6 | 磁盘 / 内存 | 磁盘满 = 写入静默失败;内存耗尽 = 被 OOM 杀掉 |
| 7 | 上游依赖 | 模型 API / 第三方服务超时 = 不是你的问题,但要能识别 |
三、每步的具体动作
1 心跳: date -u 与心跳文件里的 ts 对比(注意时区)
2 指纹: sha256(机器 id + 部署路径 + 密钥) 与名册对比
3 队列: ls queue/ | wc -l 看堆积;tail -f worker.log 看是否有消费
4 版本: cat VERSION 与心跳里的 version 字段对比
5 出口: curl -sS -m 8 "$UPSTREAM_HEALTH_URL" -o /dev/null -w "%{http_code}"
6 磁盘内存: df -h / 与 free -m(Mac 用 vm_stat)
7 上游: tail -200 logs/upstream.log | grep -i timeout
四、三个最常见的根因
根因一:时间不同步
机器时钟偏了几分钟,心跳时间戳看起来「在未来」或「在过去」,于是被判为掉线。这类问题最隐蔽,因为一切看起来都正常。
根因二:依赖版本悄悄变了
某次自动更新把依赖升了一个小版本,行为变了但没有报错。表现是「任务跑完了但产出是空的」。
根因三:静默崩溃
脚本 catch 住了异常、没有退出码、也没有写日志。系统认为任务成功,实际上什么都没做。这是三种里最贵的,因为它不会被发现,直到你有一天需要那个产出。
五、怎么让下次不用人查
排查手册的价值是「这次能修好」,但对团队真正的价值是「下次不用修」。三个机制:
- 心跳超时自动告警:超过 N 个周期没上报,直接进告警列表,而不是等你看板时发现。
- 失败原因必填:任务失败必须分类(依赖 / 超时 / 逻辑 / 外部接口),空着不允许关闭。
- 重试有上限:无限重试会把一个错误放大成一百条日志,最后没人看。
六、一张可复制的排查卡
【掉线排查卡】
□ 分型:假掉线 / 真掉线 / 半掉线
□ 1 心跳时间戳(时区!)
□ 2 身份指纹与名册
□ 3 队列深度与消费进程
□ 4 版本漂移
□ 5 网络出口(curl 8 秒超时)
□ 6 磁盘 / 内存
□ 7 上游依赖超时
□ 结论:根因 = ________ 影响范围 = ________
□ 是否已加告警 / 是否已写失败分类(是/否)
把这张卡贴在值班文档里。下一次掉线,先照着走一遍,再决定要不要叫醒人。
PUT IT IN THE SYSTEM
这篇里的东西,战簿里是现成的
窗口倒排、晨会一屏、审批队列、失败审计——不是方法论,是可运行的模块。先看在线看板,再决定要不要装。
术语看不懂?作战术语表(20 条) · 免费模板