GB28181 跨不对称链路倍速拉流:UDP丢包→TCP断连→录像截断

@

前言

我在做视频平台的现场交付时,遇到了跨网级联下载历史录像严重不稳定的问题。上下游均为 WVP-GB28181 平台,底层依赖 ZLMediaKit 流媒体服务,部署在安全网与感知网之间,跨网段级联,上下行带宽严重不对称。头疼的是,这些故障在开发环境里复现不了,到了现场才批量爆发。

本文复盘了这个过程。

一、背景

视频平台的现场交付中,跨网级联下载历史录像不稳定。用户以 8 倍速或 16 倍速下载历史视频。

二、下载视频大量丢帧:UDP → TCP

我们最开始使用 UDP 进行下载。发现下载视频中间有大量丢帧,影响用户使用。
首先排查网络。tcpdump 分段抓包,统计 RTP 序列号的连续性,确实能观测到批量丢包,严重时丢包率不低。
由此分析出大量丢帧是由于UDP丢包导致,可以换成TCP通信, 解决丢包的问题。
切换成 TCP 之后,UDP 丢包问题解决了。有遇到信息问题:下载经常断开,概率很高。
又回到网络排查的思路上:

  1. 参数试错:关闭 ZLMediaKit 的 paced_sender_ms 平滑发送、把 HTTP keepalive 从 30 秒延长到 180 秒,断连概率轻微下降但远未根治;
  2. 抓包排除:反复抓包、逐节点排查网络层,确认不是防火墙、交换机、链路抖动的问题。

两步排查走完,开始怀疑不是网络层的问题。

三、问题一:中途断连

分析

接下来在流媒体推流模块加日志后,断开前的 pattern 很清晰:发送缓冲区持续增长 → write() 返回异常 → 应用层主动 close()
由于上级平台接收速度慢,导致数据不能及时发送出去,TCP 滑动窗口逐渐缩小,下级内核发送缓冲区最终堆满,应用层捕获异常后主动断开连接。

修复

流媒体服务器做如下改动:推流时判断前次数据是否已发送完成。每次推流前检查上次发送是否完成,如果未完成,则等待一段时间,不往 socket 里塞新数据。以本地发送完成状态做自我节流。不需要探测对端,不需要改协议。
修复后,中途断连问题解决。

四、问题二:提前结束

现象

断连修完之后,过一段时间,又暴露出来一个问题:下载完成后,文件的时长偶尔小于期望,极端情况下1小时能小3分钟以上。严重影响用户使用。

分析

排查 GB28181 的下载完成机制后发现:下级平台流媒体推送完成后,立即触发完成回调给国标信令平台,信令平台发送 SIP MESSAGE(121)通知给上级,结束下载。但 SIP 信令和 RTP 媒体走两套独立通道——下级发完最后一帧就发 121,信令先发到上级平台,结束下载,文件截断。

修复

第一步:流媒体服务器在推流完成后,不立即触发完成回调,而是等发送缓冲区真正清空——确认数据已经从 socket 发出去了——再触发回调。

第二步:上级平台侧在收到 SIP 121 通知后,延迟一段时间再结束下载,让在途数据有最后到达的机会。

改造前后的时序差异:

sequenceDiagram participant 下级平台 participant 网络 participant 上级平台 rect rgb(255, 235, 238) Note over 下级平台,上级平台: 改造前:信令跑赢媒体帧,录像截断 下级平台->>网络: 推送最后一批RTP媒体帧 下级平台->>上级平台: 立即下发SIP 121结束通知 上级平台->>上级平台: 收到通知,关闭文件写入 Note over 网络: 滞后RTP帧直接丢弃 end rect rgb(232, 245, 233) Note over 下级平台,上级平台: 改造后:缓冲区排空再发信令,延时兜底 下级平台->>网络: 推送最后一批RTP媒体帧 Note over 下级平台: 等待socket内核缓冲区完全排空 下级平台->>上级平台: 下发SIP 121结束通知 Note over 上级平台: 延时窗口等待在途数据 网络->>上级平台: 全部媒体帧接收完成 上级平台->>上级平台: 正常关闭,生成完整录像 end

修复之外,还做了几项配套调整:ZLMediaKit 的 paced_sender_ms 平滑发送参数优化、HTTP keepalive 超时延长,辅助缓解高倍速下缓冲区压力;倍速拉流时根据上游实际接收吞吐动态限制推送速率,避免下游无脑满速推送;对齐上下游 RTP SSRC 标识,消除流匹配的隐性异常。这些不是主修复,但少了它们,极端场景下仍然可能触发边界问题。

落地效果

  • UDP 丢包:切换 TCP 后彻底解决
  • TCP 中途断连:发送端节流机制上线后未再复现
  • 录像截断:双层时序防护上线后,取证录像100% 完整,不再出现时长缺失
  • 性能:整套逻辑改造为应用层纯逻辑,无额外 CPU、内存开销,平台并发承载能力不受影响

五、回头看

整条链路走下来,四个阶段:UDP 丢包 → 切 TCP → 中途断连 → 提前结束。后面两个问题排查成本远高于修复成本,各自只有几行代码的改动量。

几条踩过的坑,后来在其他项目里反复验证过:

  1. 不要迷信 TCP 万能。

TCP 只解决网络层的丢包重传和拥塞控制,不负责应用层的收发速率匹配。高速、不对称链路场景下,应用层必须自己做发送节奏管控——确认上一批发出了再推下一批。换了协议只是换了一组问题,真正要修的是应用层对底层状态的感知能力。

这件事的通用形式是:任何跨网数据传输,只要带宽不对称且速率高,应用层必须实现某种形式的背压,不能假设 TCP 会替你搞定一切。

  1. 双通道协议里,控制通道与数据通道的时序没有天然保证。

GB28181 的 SIP 信令和 RTP 媒体走两套独立通道,SIP 畅通不代表 RTP 也畅通。下游"发完"和上游"收完"之间在不对称链路上可以差几十到几百毫秒。

结束类信令的发送时机必须绑定数据通道的实际完成状态,而不能绑定"我写完了"这个应用层事件。 这个原则适用于所有控制面与数据面分离的协议——不只是 GB28181。

  1. 前置故障会完全掩盖后续故障。
    连接频繁断开的时候,永远观察不到"下载完成但时长不对"的规律。修一个才能暴露下一个。

这意味着两件事:一是不要把"修完一个问题就没事了"当成默认假设,二是排查时如果只测单次成功率,很可能漏掉"能跑完但结果不对"的隐性 bug。验证方案要覆盖完整链路,不能只测"能不能通"。


做 GB28181、WVP 流媒体落地的同行,有没有踩过跨网倍速回放或信令时序的坑?欢迎评论区交流你遇到的奇葩问题。

posted @ 2026-07-19 17:34  荣--  阅读(32)  评论(0)    收藏  举报