前言
我本人其实对于直播相关业务的参与度并不高,也并不了解这些直播使用的底层技术,只是偶然进入了一次webrtc技术分享会议,发现对于直播技术的探索过程是与计算机网络相关知识息息相关的,于是就进行回看记录总结,希望能与各位分享。
正文
直播技术分类
当前市面上直播相关产品有很多种,站在使用者的角度,在使用场景上无非是1v1、1 v N、N V N。而站在技术人的角度,这些类型的产品它的技术方案却不一样。对比如下:
属性 | 单向直播 | 双向互动直播 |
---|---|---|
推拉流方式 | 单向推拉流 | 双向推拉流 |
延时 | 3-10S | 1S以内 |
网络传输协议 | RTMP+TCP | RTCP(RTP)+UDP |
单向推拉流(泛直播)
如下图所示,为一个简单的泛直播发起端到接收端的流程,其中的每一个步骤单拿出来都有很多的技术点。编码是为了减少音视频所占用的体积,使用不同的算法对数据进行压缩;网络层面的数据传输在应用层则是使用rtmp来应对,使用cdn来提高下游拉流效率。
在这其中会存在的一些网络相关问题:
- 粘包
由于tcp可视为流式的传输层协议,因此所有基于tcp的应用层协议,都需要注意“粘包”的问题,而rtmp协议使用定长数据块的方式解决问题。
- 传输的延时累计
tcp协议是可靠的传输协议,在网络传输中如果遇到丢包或者超时,便会等待及对数据包进行排队重传,从而导致延迟不断的累计。
如何解决网络层面带来的延时?优化tcp协议的丢包重传策略,我们都知道tcp在丢包情况下采用的拥塞控制算法对应的“拥塞发生”算法非常暴力如下图所示,将发送端的发送窗口急剧缩小,导致后面延时累计。因此我们可以不再使用默认的拥塞控制算法,比如BBR
等来优化。
再不济,我们使用基于udp的rtmp协议也可以,不用发送、接收确认,不用被“君子协议”拥塞控制算法绑架,况且对于直播这种对于数据包传输可靠性没那么高的应用场景来说(当前丢了几帧,后面立刻补上了),udp算是比较适合的。
双向推拉流
实现双向推拉流目前比较常见的就是webrtc,webrtc相对基于rtmp的泛直播场景,在理想化的情况下是不需要服务端来支持的,它是一个基于web端的实时音视频解决方案,旨在不借助外部支持的情况下,仅基于浏览器中内置的js api就能实现双向音视频通信,而且基于浏览器的特性也顺便支持了跨平台的特性。如下图所示,是一个理想化的webrtc场景。
面临的互相发现问题
上面的交互方式在当前的互联网场景下存在什么问题呢?显而易见,只有两台拥有公网ip的机器或者在同一个局域网内的两台机器才能实现实时的“发现”对方,发起双向音视频通信,不然是无法完成的。
由于ipv4地址数量的问题,我们每个接入互联网的个人电脑都需要通过nat地址转换协议。
nat地址转换技术简要介绍:
如下图所示假设A主机想访问互联网服务器C,那么首先它首先把消息发出给NAT路由器。路由器记录了它的内网地址和端口,并且给它分配一个全局地址和全局端口。这个地址关系记录在NAT路由表中。之后按照目的地址发给服务器。一段时间之后,服务器回应了请求给NAT路由器,那么路由器根据目的地址和端口(此时是全局的)按照NAT路由表转换为对应的主机地址,再发送给主机,这样主机就收到了服务器的回应。
因此如何将自己的机器与互联网中的另外一台机器建立起网络连接,这就是peer-to-peer需要面临的经典“nat打洞”问题。肯定还是需要借助服务器帮助的,通过中间服务器,交换两边机器的“地址”信息,然后建立tcp长连接,使用keep-alive参数保证。而nat的多种类型,导致真实场景远比想想中复杂的多。
锥型NAT,有完全锥型、受限制锥型、端口受限制锥型三种:
- Full Cone NAT(完全圆锥型):从同一私网地址端口192.168.0.8:4000发至公网的所有请求都映射成同一个公网地址端口1.2.3.4:62000 ,192.168.0.8可以收到任意外部主机发到1.2.3.4:62000的数据报。
- Address Restricted Cone NAT (地址限制圆锥型):从同一私网地址端口192.168.0.8:4000发至公网的所有请求都映射成同一个公网地址端口1.2.3.4:62000,只有当内部主机192.168.0.8先给服务器C 6.7.8.9发送一个数据报后,192.168.0.8才能收到6.7.8.9发送到1.2.3.4:62000的数据报。
- Port Restricted Cone NAT(端口限制圆锥型):从同一私网地址端口192.168.0.8:4000发至公网的所有请求都映射成同一个公网地址端口1.2.3.4:62000,只有当内部主机192.168.0.8先向外部主机地址端口6.7.8.9:8000发送一个数据报后,192.168.0.8才能收到6.7.8.9:8000发送到1.2.3.4:62000的数据报。
- 把所有来自相同内部IP地址和端口号,到特定目的IP地址和端口号的请求映射到相同的外部IP地址和端口。如果同一主机使用不同的源地址和端口对,发送的目的地址不同,则使用不同的映射。只有收到了一个IP包的外部主机才能够向该内部主机发送回一个UDP包。对称的NAT不保证所有会话中的(私有地址,私有端口)和(公开IP,公开端口)之间绑定的一致性。相反,它为每个新的会话分配一个新的端口号。
需要根据不同的nat类型,采用不同的打洞方案,具体可见参考内容。
webrtc多人会话方案
如果webrtc技术只是在nat方面需要服务器的一点小小的“协助”,如下图的mesh模式,那么在多人会话的场景下也会给端上带来很大的性能问题,因此也衍生了2和3。
-
Mesh。每个端都与其它端互连。以上图最左侧为例,5个浏览器,二二建立p2p连接,每个浏览器与其它4个建立连接,总共需要10个连接。如果每条连接占用1m带宽,则每个端上行需要4m,下行带宽也要4m,总共带宽消耗20m。而且除了带宽问题,每个浏览器上还要有音视频“编码/解码”,cpu使用率也是问题,一般这种架构只能支持4-6人左右,不过优点也很明显,没有中心节点,实现很简单。
-
MCU (MultiPoint Control Unit)
这是一种传统的中心化架构(上图中间部分),每个浏览器仅与中心的MCU服务器连接,MCU服务器负责所有的视频编码、转码、解码、混合等复杂逻辑,每个浏览器只要1个连接,整个应用仅消耗5个连接,带宽占用(包括上行、下行)共10m,浏览器端的压力要小很多,可以支持更多的人同时音视频通讯,比较适合多人视频会议。但是MCU服务器的压力较大,需要较高的配置。 -
SFU(Selective Forwarding Unit)上图右侧部分,咋一看,跟MCU好象没什么区别,但是思路不同,仍然有中心节点服务器,但是中心节点只负责转发,不做太重的处理,所以服务器的压力会低很多,配置也不象MUC要求那么高。但是每个端需要建立一个连接用于上传自己的视频,同时还要有N-1个连接用于下载其它参与方的视频信息。所以总连接数为5*5,消耗的带宽也是最大的,如果每个连接1M带宽,总共需要25M带宽,它的典型场景是1对N的视频互动。
总结
这篇文章借助直播技术学习,发现了在直播技术探索中遇到的很多网络上的问题,包括传输层协议tcp特性:丢包重传、拥塞控制、流式传输带来的延时累计、应用层粘包等问题。也有webrtc中遇到的nat技术带来的如何在peer-to-peer场景中互相发现的难题,大数据量的传输问题。希望跟大家一起以点知面,借助这些真实的场景完善自己的网络相关知识。正如上面直播技术演进中对于网络问题的探索,感觉一些生硬的知识,只有在遇到相应的问题时才能感受到学习他带来的愉悦感。
参考:
nat打洞: https://www.cnblogs.com/GO-NO-1/p/7241556.html
webrtc多方会话方案:https://www.cnblogs.com/yjmyzz/p/webrtc-multiparty-call-architecture.html