边缘设备连续掉线 8 小时的完整复盘:从"重启就好"到"根因修复"
越微智能(Yuewell)工业边缘 AI 工程实践系列 · 第 6 篇
关键词:事故复盘、掉线、systemd 重启风暴、维护锁、网络恢复、RTSP 重连、看门狗
一、事故概述:一个"重启就好"的问题,持续了 8 小时
2026 年 6 月,我们的一个垃圾转运站项目现场,一台 RK3588 边缘 AI 设备出现了连续掉线的问题。
现象:
- 设备每隔 30-60 分钟掉线一次,平台显示"设备离线"
- 每次掉线后,大约 2-5 分钟自动恢复
- 现场人员 SSH 上去看,进程都在,端口都在监听,但平台就是连不上
- 现场人员的第一反应是"重启就好",但重启后过一段时间又掉线
- 这个问题从早上 8 点持续到下午 4 点,整整 8 小时,期间设备累计离线时间超过 2 小时
客户的投诉:
“你们这个设备怎么回事?一天掉好几次线,我们的巡检数据都断了。每次都是重启就好,但过一会儿又掉。你们能不能彻底解决一下?”
这是一个典型的"间歇性故障"——不是完全不工作,而是时好时坏,每次都能"重启就好",但根因没有找到,问题持续存在。
本文完整复盘这次事故的排查过程、根因分析、修复方案,以及我们从中沉淀的工程规范。
二、第一阶段排查:“进程都在,为什么平台连不上?”
2.1 初步排查
现场人员 SSH 上去后,做了以下检查:
# 1. 检查进程psaux|grepyw_# 结果:yw_core 和 yw_algo_server 都在运行# 2. 检查端口ss-tlnp|grep5005# 结果:50051 和 50052 都在监听# 3. 检查 UDS 套接字ls-l/tmp/yw_algo_fd.sock# 结果:文件存在# 4. 检查日志tail-50logs/yw_core_20260608.log# 结果:没有明显的错误日志所有检查都显示"一切正常",但平台就是连不上。这时候现场人员的判断是:“可能是网络问题,重启一下就好。”
重启后确实恢复了,但过了 40 分钟又掉线了。
2.2 关键发现:掉线时的日志
第二次掉线时,现场人员没有立即重启,而是先抓了完整的日志。这是整个排查过程中最关键的一步。
# 掉线时,查看最近 500 行日志grep-E'ERROR|WARN|FATAL|disconnect|offline|reconnect'logs/yw_core_*.log|tail-100关键日志片段:
[2026-06-08 10:23:15] [INFO] [PlatformClient] 平台心跳超时,开始重连... [2026-06-08 10:23:16] [INFO] [PlatformClient] 重连平台 ws://platform.xxx.com:8080/ws [2026-06-08 10:23:17] [ERROR] [PlatformClient] 重连失败:Connection refused [2026-06-08 10:23:20] [INFO] [PlatformClient] 重连平台 ws://platform.xxx.com:8080/ws [2026-06-08 10:23:21] [ERROR] [PlatformClient] 重连失败:Connection refused ...(重复 10 次) [2026-06-08 10:24:30] [INFO] [PlatformClient] 重连成功,设备上线关键发现:不是设备"掉线",而是设备到平台的 WebSocket 连接断了,重连失败了大约 1 分钟,然后自动恢复了。平台显示"设备离线"是因为 WebSocket 断连,而不是设备本身不工作。
2.3 为什么重连会失败 1 分钟?
进一步排查发现,重连失败的原因是DNS 解析失败:
# 掉线时测试 DNSnslookupplatform.xxx.com# 结果:;; connection timed out; no servers could be reached现场的网络环境是:设备通过 4G 路由器上网,DNS 服务器配置的是运营商的 DNS。4G 网络不稳定时,DNS 解析会超时。
但这还不是完整的根因——因为 DNS 恢复后,重连应该立即成功,不应该持续 1 分钟。
三、第二阶段排查:systemd 重启风暴
3.1 发现重启风暴
继续查看 systemd 日志:
journalctl-uyw-avis-backend.target--since"2026-06-08 10:00"--until"2026-06-08 11:00"关键发现:
10:23:15 yw_core[12345]: 平台心跳超时,开始重连... 10:23:17 yw_core[12345]: 重连失败:Connection refused 10:23:18 systemd[1]: yw-core.service: Main process exited, code=killed, status=9/KILL 10:23:18 systemd[1]: yw-core.service: Failed with result 'signal'. 10:23:28 systemd[1]: yw-core.service: Scheduled restart job, restart counter is at 3. 10:23:28 systemd[1]: Stopped Yuewell AI Vision Core Service. 10:23:28 systemd[1]: Started Yuewell AI Vision Core Service. 10:23:29 yw_core[12400]: 启动中... 10:23:30 yw_core[12400]: Preflight Check: PASS 10:23:31 yw_core[12400]: 连接推理引擎... 10:23:31 yw_core[12400]: UDS 套接字就绪 10:23:32 yw_core[12400]: 加载任务配置... 10:23:33 yw_core[12400]: 启动 RTSP 拉流... 10:23:35 yw_core[12400]: 连接平台... 10:23:36 yw_core[12400]: 平台连接成功 10:23:36 yw_core[12400]: 设备上线关键发现:yw_core 进程被 SIGKILL(信号 9)杀掉了!不是正常退出,是被强杀的。
3.2 谁杀了进程?
继续排查:
# 查看 OOM Killer 日志dmesg|grep-i'oom\|killed'|tail-20结果:
[10:23:18] Out of memory: Killed process 12345 (yw_core) total-vm:524288kB, anon-rss:385024kB, file-rss:0kB, shmem-rss:0kB [10:23:18] oom_reaper: reaped process 12345 (yw_core), now anon-rss:0kB根因找到了:OOM Killer 杀掉了 yw_core 进程!
设备的物理内存是 4GB,yw_core 进程占用了 385MB(anon-rss),看起来不算多。但为什么会 OOM?
3.3 内存泄漏的真相
继续查看内存使用历史:
# 查看 yw_core 进程的内存使用趋势grep'memory_usage\|rss'logs/yw_ops.log|tail-50发现:
08:00:00 yw_core RSS: 185MB 09:00:00 yw_core RSS: 245MB 10:00:00 yw_core RSS: 310MB 10:23:18 yw_core RSS: 385MB → OOM Killedyw_core 进程的内存使用在持续增长,每小时增长约 60MB。这是典型的内存泄漏。
3.4 内存泄漏在哪里?
进一步分析代码,发现内存泄漏在RTSP 拉流重连逻辑中:
- 当 RTSP 连接断开时,代码会重新创建一个拉流会话
- 但旧的会话没有正确释放——FFmpeg 的
AVFormatContext、AVCodecContext、帧缓冲区都没有释放 - 每次重连泄漏约 5-10MB
- 现场 4G 网络不稳定,RTSP 频繁断连重连,内存泄漏加速
这就是完整的事故链:
4G 网络不稳定 │ ├── RTSP 频繁断连重连 → 每次重连泄漏 5-10MB → 内存持续增长 │ │ │ └── 2 小时后内存耗尽 → OOM Killer 杀掉 yw_core │ └── WebSocket 平台连接断连 → DNS 解析超时 → 重连失败 1 分钟 │ └── 平台显示"设备离线"两个问题叠加,导致了"设备频繁掉线"的现象。
四、第三阶段排查:为什么重启后 40 分钟又掉线?
找到 OOM 根因后,还有一个问题没解释:为什么重启后 40 分钟又掉线?
重启后内存应该是干净的,不应该 40 分钟就 OOM。
继续排查,发现了第二个问题:systemd 重启风暴 + 维护锁误触发。
4.1 重启风暴
OOM 杀掉 yw_core 后,systemd 的Restart=on-failure会在 10 秒后自动重启。但重启后:
- RTSP 拉流重新建立
- 如果网络还是不稳定,RTSP 继续频繁断连
- 内存泄漏继续
- 这次因为初始内存已经有一些基础占用,加上泄漏速度更快(网络更差时重连更频繁),40 分钟就再次 OOM
这就形成了重启风暴:OOM → 重启 → 40 分钟后再次 OOM → 再次重启……
4.2 维护锁误触发
还有一个更隐蔽的问题:维护锁误触发。
我们的维护锁机制是:systemctl stop时创建维护锁,systemctl start时删除维护锁。但 OOM Killer 杀掉进程时,不经过ExecStopPost,所以不会创建维护锁——这是正确的设计。
但问题出在:现场人员手动systemctl stop做排查时,创建了维护锁,然后排查完忘记systemctl start,而是直接reboot了设备。
设备重启后,维护锁文件还在(因为锁文件存在磁盘上,重启不丢失)。systemd 启动服务时,ExecStartPre检测到维护锁存在,拒绝启动。
结果:设备重启后,yw_core 服务没有启动,平台显示"设备离线"。现场人员以为是"又掉线了",再次重启,还是一样。直到我们远程排查发现维护锁的存在,手动删除后才恢复。
这是一个典型的运维操作不规范导致的二次故障。
五、根因总结与修复方案
5.1 三个根因
| # | 根因 | 影响 | 严重程度 |
|---|---|---|---|
| 1 | RTSP 重连时 FFmpeg 资源未释放,内存泄漏 | 每小时泄漏 60MB,2 小时 OOM | 🔴 高 |
| 2 | 4G 网络不稳定导致 RTSP 频繁断连,加速内存泄漏 | 泄漏速度从 60MB/h 提升到 100MB/h | 🟡 中 |
| 3 | 维护锁在 reboot 后残留,导致服务拒绝启动 | 设备重启后服务不启动,平台离线 | 🟡 中 |
5.2 修复方案
修复 1:RTSP 重连资源释放(根因 1)
- 重连时,先调用
avformat_close_input释放旧的AVFormatContext - 调用
avcodec_free_context释放旧的AVCodecContext - 调用
av_frame_free释放所有未处理的帧缓冲区 - 增加资源泄漏检测:每次重连后打印当前内存使用,异常时告警
- 增加重连频率限制:1 分钟内重连超过 5 次时,退避到 30 秒重连一次,避免频繁重连加速泄漏
修复 2:网络不稳定时的退避策略(根因 2)
- RTSP 断连后,采用指数退避重连:1s → 2s → 4s → 8s → 最大 30s
- 网络恢复后,逐步恢复到正常重连间隔
- 增加网络质量监控:持续检测 ping 延迟和丢包率,网络质量差时降低分析帧率(从 10fps 降到 5fps),减少 RTSP 带宽需求
修复 3:维护锁启动时自动清理(根因 3)
ExecStartPre检测到维护锁时,不再直接拒绝启动,而是检查锁文件的时间戳- 如果锁文件存在超过 10 分钟(说明是异常残留,不是正在维护),自动删除并继续启动
- 如果锁文件存在不足 10 分钟(可能是正在维护),拒绝启动并输出明确提示
- 增加
maintenance.lock的 TTL 机制:锁文件创建时写入过期时间,过期后自动失效
5.3 额外加固:内存压力软降级
除了修复根因,我们还增加了内存压力软降级机制:
- 进程内监控自身 RSS 内存使用
- 内存达到 warn 阈值(70%)时:降低预览帧率、释放 JPEG 缓存、暂停非关键任务
- 内存达到 critical 阈值(85%)时:主动关闭部分 RTSP 拉流会话,释放内存
- 内存恢复后,逐步恢复正常运行
这个机制不能替代内存泄漏修复,但可以作为"最后一道防线",在内存泄漏被发现和修复之前,避免 OOM Killer 强杀进程导致的服务中断。
六、事故时间线完整复盘
| 时间 | 事件 |
|---|---|
| 06-08 08:00 | 设备正常运行,yw_core RSS 185MB |
| 06-08 09:00 | 4G 网络开始不稳定,RTSP 频繁断连,yw_core RSS 245MB |
| 06-08 10:00 | yw_core RSS 310MB,平台 WebSocket 开始间歇性断连 |
| 06-08 10:23 | yw_core RSS 385MB,OOM Killer 杀掉进程,平台显示离线 |
| 06-08 10:24 | systemd 自动重启 yw_core,设备恢复上线 |
| 06-08 11:00 | 现场人员手动 stop 排查,创建维护锁,然后 reboot 设备 |
| 06-08 11:02 | 设备重启后,维护锁残留,yw_core 拒绝启动,平台离线 |
| 06-08 11:30 | 现场人员再次重启,问题依旧,电话求助 |
| 06-08 12:00 | 我们远程登录,发现维护锁残留,手动删除,服务启动 |
| 06-08 12:10 | 设备恢复上线,但内存泄漏根因未修复 |
| 06-08 13:00 | yw_core RSS 再次增长到 280MB |
| 06-08 14:00 | 我们远程部署修复版本(RTSP 资源释放 + 退避策略) |
| 06-08 14:30 | 修复版本上线,内存使用稳定在 200MB 左右 |
| 06-08 16:00 | 连续运行 1.5 小时无内存增长,事故确认解决 |
七、越微自研:Yuewell-Incident 故障诊断与恢复规范
这次事故后,我们沉淀了Yuewell-Incident 故障诊断与恢复规范,核心包括:
- 三级故障分类:P0(完全不可用)/ P1(部分功能异常)/ P2(性能下降),不同级别有不同的响应时间和处理流程
- 故障排查五步:① 抓日志不重启 → ② 查进程/端口/资源 → ③ 查 systemd/OOM/dmesg → ④ 查网络/DNS/连接 → ⑤ 查代码/配置变更
- 内存泄漏检测:进程内 RSS 监控 + 定时日志 + 异常告警,内存持续增长时自动触发诊断
- RTSP 重连退避:指数退避 + 重连频率限制 + 资源释放校验,杜绝重连泄漏
- 维护锁 TTL 机制:锁文件带过期时间,启动时自动清理过期锁,杜绝残留锁导致服务不启动
- 内存压力软降级:warn/critical 两级阈值,自动降帧/释放缓存/关流,避免 OOM 强杀
- 事故复盘模板:时间线 / 根因 / 影响 / 修复 / 加固 / 预防,每次事故必须输出复盘文档
这套规范让我们的现场设备从"出问题靠重启",变成了"出问题有诊断、有恢复、有复盘、有预防"。在后续的项目中,类似的内存泄漏问题在上线前就被检测到,没有再造成现场事故。
八、写在最后
边缘设备的故障排查,最忌讳的就是"重启就好"。重启确实能解决很多问题,但它也会抹掉故障现场,让根因永远找不到。问题不会因为重启而消失,它只会在下次更严重的时候爆发。
越微智能在 RK3588 边缘 AI 视觉设备的量产交付中,经历了从"出问题就重启"到"出问题先抓日志再排查"的完整演进,把这些踩过的坑沉淀成了 Yuewell-Incident 故障诊断与恢复规范。我们相信,故障诊断和恢复能力是边缘 AI 产品从"能交付"到"能运维"的核心服务能力。
如果你也在做边缘设备的生产化运维,欢迎交流。
关于作者:越微智能(Yuewell)专注具身智能与工业 AI 视觉落地,基于自研 VLA 多模态大模型,提供全品牌机器人二次开发(适配宇树/优必选/智元/傅利叶)与工业级视觉算法定制,支持从算法、硬件到产线实机部署的全栈交付。