搭建实时网络

为什么网络在实时通信中如此重要? #

网络是实时通信中的限制因素。在理想的世界中,我们将拥有无限的带宽,并且数据包会即时到达。但事实并非如此。网络是受限的,且其限定条件随时可能更改。测量和观察网络状况也是一个难题。根据您所使用的硬件,软件及其配置,您可能看到不同的表现。

实时通信也带来了其他大多数领域中不存在的问题。对于网站开发人员来说,如果您的网站在某些网络上运行速度较慢,那不是致命问题。只要所有数据到达,用户都会感到满意。但对于WebRTC,如果您的数据延迟了,那就没用了。没有人在乎5秒钟前的电话会议中所说过的话。因此,在开发RTC(实时通信)系统时必须权衡。我的时间限制是多少,可以发送多少数据?

本章介绍了适用于数据和媒体通信的概念。在后面的章节中,我们将超出理论范围,讨论一下WebRTC的媒体和数据子系统如何解决这些问题。

使网络变得困难的有哪些属性? #

在所有网络上都能有效工作的代码很复杂。您会面对许多不同的因素,它们都可以相互影响。这些是开发人员将遇到的最常见问题。

带宽 #

带宽是可以在给定路径上传输的最大数据速率。请记住,这也不是一个静态数字,这一点很重要。随着越来越多(或更少)的人使用带宽,带宽将沿路由变化。

传输时间 #

传输时间指的是一个数据包需要多长时间到达。像带宽一样,这不是恒定的。 传输时间随时可能波动。

抖动 #

抖动是每个数据包的传输时间可能会有所不同的现实表现。您的数据包可能会延迟,但随后会突然大量集中到达。

数据包丢失 #

数据包丢失是指消息在传输中丢失。数据损失率可能是稳定的,也可能出现波峰和波谷。 这可能是由于网络类型的原因造成的,例如卫星或Wi-Fi等。或者也可能是传输路径上的软件导致的。

最大传输单位(MTU) #

最大传输单位指的是单个数据包大小的限制。网络不允许您发送一个巨大的消息。在协议级别,消息可能必须被拆分为多个较小的数据包。

根据您采用的网络路径,MTU也将有所不同。您可以使用MTU路径发现之类的协议来确定可以发送的最大数据包大小。

拥塞 #

拥塞是指网络达到极限时的情况。这通常是因为您已达到当前路由可以处理的峰值带宽。或者可能是运营商对您的ISP配置导致,比如限制了每小时的流量。

拥塞会以多种不同的方式展现出来。没有标准化的表现。在大多数情况下,当拥塞发生时,网络将丢弃多余的数据包。在其他一些情况下,网络将缓存数据包。这将导致数据包的传输时间增加。随着网络的拥塞,您还会看到更多的抖动。这是一个快速变化的领域,并且还有其他用于拥塞检测的新算法目前仍在编写中。

动态变化 #

网络是动态的,各种状况可能会迅速变化。在通话过程中,您可能会发送和接收数十万个数据包。 这些数据包可能经过多个跃点。这些跃点可能由数百万其他用户共享。即使在您的本地网络中,您也可能正在下载高清电影,或者可能有设备正要下载软件更新。

保证通话质量不能仅仅是在启动时简单的度量您的网络。您需要持续不断的评估。还需要处理来自于多种网络硬件和软件的所有不同表现。

解决数据包丢失问题 #

数据包损失是最需要解决的首要问题。有多种解决方法,每种方法都有自己的优势。这取决于您要发送的内容以及对延迟的容忍度。同样重要的一点是,并非所有数据包丢失都是致命的。丢失一些视频可能不是什么问题,人眼甚至可能无法感觉到。但丢掉用户的短信就是不可接受的了。

假设您发送了10个数据包,而数据包5和6丢失了。下面是一些解决问题的方法。

确认(Acknowledgments) #

确认是指接收方收到每个数据包时,都去通知发送方。如果发送方收到一个数据包的两次确认消息,且该数据包不是最终数据包时,发送方就会意识到有数据包已经丢失。例如,当发送方两次收到数据包4的ACK消息时,它就知道接收方没有收到数据包5。

选择性确认(Selective Acknowledgments) #

选择性确认是对确认的改进。接收方可以发送一个SACK消息来确认多个数据包已经收到,并通知发送者间隔时间。 例如,发送方可能收到一个包含数据包4和7的SACK消息。这样它就知道需要重新发送数据包5和6。

否定应答(Negative Acknowledgments) #

否定应答以相反的方式解决了问题。接收方并不通知发送方自己已经收到了什么,而是通知发送方丢失了什么。在我们的例子里,将为数据包5和6发送一个NACK。发送方仅知道接收方希望再次发送的数据包。

前向纠错(FEC) #

前向纠错可以抢先解决丢包问题。发送方将发送冗余数据,这意味着部分数据包丢失不会影响最终流。一种流行的算法是Reed–Solomon纠错算法。

这减少了发送和处理确认的延迟/复杂度。如果您所在的网络的损耗为零,则前向纠错会浪费带宽。

解决抖动问题 #

大多数网络都存在抖动。即使在局域网内部,您也有许多设备以变化的速率发送数据。您可以通过运行ping命令对其他设备执行ping操作,并注意往返延迟的波动,从而轻松地观察到抖动。

要解决抖动的客户端,请使用JitterBuffer。JitterBuffer确保数据包的稳定传递时间。不利的一面是,JitterBuffer为提前到达的数据包增加了一些延迟。 好处是延迟的数据包不会引起抖动。想象一下,在通话期间,您可能会看到数据包到达时间类似下面这样。

* time=1.46 ms
* time=1.93 ms
* time=1.57 ms
* time=1.55 ms
* time=1.54 ms
* time=1.72 ms
* time=1.45 ms
* time=1.73 ms
* time=1.80 ms

在这个例子里,~1.8 ms是一个不错的选择。较晚到达的数据包将使用我们的延迟窗口。较早到达的数据包将被延迟,并可以填充由较晚的数据包耗尽的延迟窗口。这意味着我们不会再陷入无数据包可用的困境,可以为客户提供顺畅的传输率。

检测拥塞问题 #

在我们解决拥塞问题之前,我们需要先检测到拥塞。为了检测到它,我们使用拥塞控制器。这是一个复杂的主题,并且仍在迅速变化中。 一些新算法仍在持续被发布和测试。总的来看,它们都以相同的方式运行。即是说,拥塞控制器在给定某些输入的情况下提供带宽估计值。 这里是一些可能的输入。

  • 数据包丢失 - 随着网络逐渐变得拥塞,数据包开始被丢弃。
  • 抖动 - 随着网络设备变得越来越过载,将导致数据包排队时间变得不稳定。
  • 封包往返时间(RTT) - 拥塞时,数据包将需要更长的时间才能到达。与抖动不同的是,往返时间是持续增加的。
  • 显式拥塞通知(ECN) - 较新的网络可能会将数据包标记为有拥塞造成丢失的风险,这样可以缓解拥塞。

这些值需要在通话期间持续不断的测量。网络的利用率可能会增加/减少,因此可用带宽可能会不断变化。

解决拥塞问题 #

现在我们有了一个估计的带宽值,我们需要调整发送的内容。如何调整取决于我们要发送的数据类型。

降低发送速度 #

限制发送数据的速度是防止拥塞的第一个解决方案。拥塞控制器为您提供了带宽的估计值,发送方有责任对发送速率进行限制。

这是适用于大多数数据通信的方法。对于像TCP这样的协议,这全部由操作系统完成,并且对用户和开发人员完全透明。

减少发送的数据 #

在某些情况下,我们可以发送更少的信息来满足我们的限制。对于数据的到达时间,我们可能有严格的限制,因此我们发送速度不能太慢。这些是实时媒体所受的限制。

如果我们没有足够的可用带宽,我们可以降低发送的视频质量。这要求您的视频编码器和拥塞控制器之间存在紧密的反馈回路。