背景

本文主要面向音视频初学者,讲明白下面几个问题:

  1. 面试常见问题:为什么 TCP 传输的延时比 UDP 大 ?
  2. 直播的延时往往在 1s 以上,根本原因在哪里 ?
  3. RTC 实时通信的延时要求在 400ms 以内,是怎么做到的 ?

引子

我们先聊聊网上购物,一份快递从发货到送达的耗时优化

谈谈网络通信中的延时优化_优化在快递站入库和逗留的时间太长 ?—— 比如,每个快递件入库半天堆积 1 天再才转派发如图,我们看看,有哪些可能的因素会影响快递从商家 A 传递到消费者 B 的手中的时间 ?

  1. 快递数量不均匀,有时候特别多(堆积如山),有时候特别少(零零散散),各节点的资源利用率未能充分发挥出来
  2. 中途发生快递丢失了,需要重新补发一份(整体时间基本上要翻倍)
  3. 运输的路线太堵,导致在路上耗费太多时间

有什么思路,一一解决上述的延时因素,以提高快递的送达速度呢 ?

  1. 提高每个快递站的吞吐量,减少每个中转站的缓存,加速快递的流转 ?
  2. 快件的揽件、传输与派送,从 “天” 的粒度拆分到更细的粒度,比如小时粒度,以追求资源的调度更动态和平滑一点 ?
  3. 每个快件同时发 2 份 ?丢了一个还可以派送另一个 ?—— 当然,负面影响是带来运力资源的增加
  4. 动态选择合适的中转运输路线,哪里不堵走哪里 ?—— 运输路线动态规划避开拥堵,这是一门艺术

从上面的探索可以看出,优化延时,我们关注的点主要是:减少中间环节的缓存,最大化提高资源的利用率,通过冗余对抗丢失,动态地规划传输路径。如果你能理解这几个抽象的点,那么恭喜,下面你就不难理解如何降低音视频的网络传输延时了。

正题

为什么 TCP 传输的延时比 UDP 大 ?

因为 TCP 保证了 “可靠传输”,当数据发生丢失后,一定会进行重传,重传带来延时(类似快递丢失补发),并且非常影响后续数据的持续及时发送;

1. 因为 TCP 有个 “缓存队列”(类似于快递站),它不会来一个数据就立马发送出去,而是先缓存起来,通过一个 “滑动窗口” 来控制发送频率(类似快递站的派送人力),在上一波数据发送完毕得到 ACK 确认后,再发送下一波数据(类似一箱快递的派送结束后再投入下一箱);而 UDP 则没有该机制,闭着眼睛发(需要抢占整个地区更多的快递员);

2. 因为 TCP 是一个 “君子”,一旦发现有丢数据或者网络不好,则主动去 “退让”,减少自己的 “滑动窗口” 大小(让出快递人力给地区其他公司),导致自己的数据发得更慢了;

直播的延时往往在 1s 以上,根本原因在哪里 ?

1. 直播底层的传输协议(RTMP)默认使用了 TCP ,引入了 TCP 上述延时大的特性

2. 由于 TCP 不丢数据的特性,会导致播放端一旦因为网络原因卡住多少秒,在播放器不追帧的情况下,后续恢复播放后就有多少秒的延时(因为这些因为网络卡住没有及时发送过来的数据不会凭空消失)

3. 为了实现播放秒开,通常直播的流媒体服务器,会缓存最近的 GOP,在播放器不追帧的情况下,会带来一个固定的延时(取决于推流端配置的 GOP 大小)

谈谈网络通信中的延时优化_通信_02

    4. 如果播放端使用的 HLS 延时,那就更大了,取决于服务端 HLS 切片的最小间隔(官方推荐 10s)

谈谈网络通信中的延时优化_网络_03

RTC 实时通信的延时要求在 400ms 以内,是怎么做到的 ?

关键词:UDP、FEC、拥塞控制、数据量调节、jitter buffer、服务的端调度和级联

1. 底层使用 UDP 代替 TCP —— 相比于 TCP 滑动窗口 “君子退让” 的特性,UDP 可以不讲武德,最大化地发送数据,提高吞吐量(提高带宽利用率)

2. 底层使用 UDP 协议,如何解决丢包重传的问题呢 ?

  • 音视频传输,为了满足低延时,首先是 “允许” 丢部分不重要的数据的,针对丢失的数据,在接收和播放端会做一些兼容性处理,如:PLC(音频包丢失的智能补偿)、视频跳过 GOP 尾部的 B/P 帧等
  • 在 UDP 之上,使用 FEC 冗余(类似多发一份快递,但更高级),可以在不重传的情况下,在接收端把丢失的数据 “恢复” 回来,相关细节我在这篇文章有详细科普:《谈谈网络通信中的 FEC 基础》
  • 当然,在 UDP 之上,依然也有使用重传来兜底的,因为 FEC 冗余会带来对带宽的资源消耗变大,因此在 RTT 网络延时较小的场合,重传依然是一个不错的选择,关于重传的更多细节可以参考我的这篇文章:《谈谈网络通信中的 ACK、NACK 和 REX》

3. 底层使用 UDP 不讲武德地发送数据,不会让网络爆掉么 ?

  • 当然会,因此,我们可以在 UDP 之上,加一些控制流量的机制,让整体地发送更加平滑,详细细节可以参考我的这篇文章:《谈谈网络通信中的流量整形》
  • 但是,如果要发送的数据量(类似快递的数量)本身就爆掉了(高于当前网络所能承载的能力),无论怎么在传输端加平滑,都解决不了拥堵的问题的,因此,RTC 最最核心的降低延时的方法之一就是:带宽探测及配套的数据量调节手段

4. 有哪些带宽探测及配套的数据量调节手段 ?

  • 带宽探测,就是动态地预估当前的网络带宽,如何做到实时地对带宽进行准确地预测,是一门值得深挖和长期研究的艺术,本文就不展开讲了,可以搜索了解 BBR、GCC 等关键词
  • 数据量调节:当探测到网络带宽不足时,可以调节数据量以防止拥塞带来的延时,通常可调节的内容包括:音视频的帧率/码率、FEC 的冗余比例、大小流等

5. 那既然 UDP 也有重传,自然也会存在网络抖动的情况下,接收和播放端被动产生被动的 buffer 数据,RTC 是如何消除掉这些被动 buffer 的呢 ?

  • 核心原理:动态 jitter buffer + TSM 时域压扩(变速不变调)算法
  • 接收端的 buffer,往往是用来抵抗网络抖动的,固定的 buffer 则带来的是固定的延时(如:必须缓冲到 500ms 的数据再输出播放),而动态的 jitter buffer 则会根据网络好坏动态调节 buffer 大小
  • TSM 时域压扩(变速不变调):则是一种不影响用户听感体验的音频播放追帧策略,类似可以做到 0.9/1.1 倍数播放,用于加快或者减慢 buffer 数据的消耗达到追帧或者降速的作用,算法科普文章可参考:《TSM时域压扩(变速不变调)算法总结》

6. 有了一系列客户端层面的延时优化,最后就剩下整体服务端流转发网络的调度和级联了,这也是一门值得深挖和长期研究的方向,这里也不长篇大论了,用一张图大致表达一下:

谈谈网络通信中的延时优化_音视频_04

小结

关于网络传输的延时相关内容就介绍到这里了,考虑篇幅,部分细节没有展开,有兴趣深挖的朋友,欢迎大家来信 lujun.hust@gmail.com 交流,另外,也欢迎大家关注我的新浪微博 @卢_俊 或者 微信公众号 @Jhuster 获取最新的文章和资讯。