6月24日,又拍云 Open Talk | 2018 音视频技术沙龙·上海站 顺利落幕,来自又拍云的 PrismCDN 项目负责人凌建发做了《又拍云低延时 WebP2P 直播技术实践》的精彩分享。

凌建发先后任职于诺基亚等通信公司,目前负责又拍云 PrismCDN 项目的设计与开发工作,对 P2P 、流媒体技术有较深入的研究。PrismCDN 是在 CDN 的基础上完美融合 P2P 及流媒体技术,高效整合利用零散闲置的上行带宽资源构建内容分发网络服务。

以下是分享内容:

WebRTC 可以有很多种的应用,比如实时音视频通信,又拍云 PrismCDN 团队目前在做把 WebRTC 应用于内容分发 CDN。利用 WebRTC DataChannel 下的一些功能,可以去建立 P2P 连接,有了这个能力之后,我们就可以在网页上面实现 P2P 的功能,也就是 WebP2P 的 H5P2P 实现。

在 CDN 网络基础上,加入 P2P 的目的是减少 CDN 的流量,用 P2P 连接完成大部分的流量。这样会带来一个巨大的好处——CDN 的成本下降,价格优势就体现出来了;对客户、对视频应用来讲,带宽成本也非常显著地下降。成本优势这一最大的好处,也是我们做 PrismCDN 这张 P2P-CDN 网络最大的动力。

我今天主要以 WebP2P 功能来切入这个话题。WebP2P 主要功能是在能够以 P2P 方式传输数据到网页上来,目的是要降低 CDN 的成本。

FlashP2P 已行至末路

举一个已经存在了八年的 WebP2P 的典型应用:FlashP2P,这是 Adobe 公司自己研发的内嵌在 Flash 播放器里面的 P2P 功能。它采用的协议是私有的 RTMFP,现在用这个协议的公司也蛮多的。

我们先看一下 Flash 的未来:Google 声明在 2020 年末就完全不支持 Flash;也是2020 年下半年,微软的 IE 和 Edge 浏览器放弃支持 Flash。

苹果的态度其实大家都很清楚,乔布斯一开始就很讨厌 Flash 这个东西。Mozilla 也是一样,2020 年结束对 Flash 的支持。Facebook 也在 2020 年末的时候停止支持 Flash 的视频游戏。最后,Adobe 自己也宣布了在 2020 年末就完全停止支持 Flash。

也就是说,在 2020 年末的时候,FlashP2P 这个产品也就基本上结束了。

那么我们如何在 Web 里面使用 P2P 呢?诞生于 2011年的 WebRTC 技术,在 Google、Microsoft、Apple、Facebook、Mozilla 等几家大公司的支持下成为了 H5 的标准,并且 Chrome、Firefox、Safari、Edge 等几大浏览器也都支持 WebRTC,我们就可以用 WebRTC 来实现 P2P 的功能了。

image.png

△ SDK P2P 示意图

基于 SDK 的 P2P 不适合网页端

在讲 WebP2P 之前,我们先讲一下基于 SDK 的 P2P 功能。它的原理是这样的, SDK 里面有一个 P2P 下载器,它能够建立 P2P 连接;P2P 不能完成所有的数据传输,不够的数据再从 CDN 服务器补充。最终拼成一个完整的数据流,这就是所谓的P2SP 技术。

我们在 SDK 里面做一些本地的转封装之后,然后通过 local(127.0.0.1) 的 HTTP Server 向播放器提供标准的 HTTP 请求,比如说 HLS 、HTTPFLV。在使用传统 CDN 服务时,播放器发起一个 HTTP 请求或者 RTMP 请求到 CDN,现在使用 SDK P2P CDN 服务后,播放器直接到本地地址(127.0.0.1)拉取一个 HTTP 请求。播放器只需要改变一下请求的 URL 就可以从传统 CDN 切换到 SDKP2P CDN。

如果要在 Web 上应用 SDK P2P 技术,只有一个方式,就是把这个 SDK 做成一个插件安装到浏览器里面去,包括用 ActiveX、NPAPI 这些技术把 SDK 嵌到浏览器里面去。

过去若干年的经验已经告诉我们,浏览器插件带来的用户体验是非常差的,最后几乎所有的视频网站没有使用。所以说用 SDK 的方式去做 WebP2P,这条路走不通的。

本质上来讲 FlashP2P 也是一个 SDK P2P,只不过说 Flash 这个插件应用太广泛了,几乎每个浏览器都会装它,没有重新安装插件的问题。

WebRTC + H5 带来了 WebP2P

有了 WebRTC 之后,通过浏览器实现点对点连接的可能性就来了。我们可以通过WebRTC + H5 的组合实现 WebP2P。

对 WebP2P 的研究,国外已经持续了一些时间了,包括 BiTorrent 也衍生出一个WebP2P 项目——WebTorrent。Peer5、Streamroot 是两家商业公司,分别拿了 250 万美元和 320 万美元的投资。



△ H5 P2P 示意图

H5P2P 用 JavaScript 实现 P2P 引擎,包括下载器、转封装。通过 WebRTC 里面的 DataChannel 功能建立 P2P 连接,从 P2P 雾节点拿数据;当 P2P 数据不足时,可以通过 WebSocket 或者 DataChannel 去 CDN 补数据;将 P2P 数据与 CDN 数据组合后得到完整的媒体数据;最后通过 MSE 转封装成 mp4 向 H5 播放器 (video标签) 提供媒体数据流。

以上就是在 H5 框架里面实现 P2P 数据层面的逻辑,P2P 里面还会有一些信令、管理服务器,通过 WebSocket 就可以建立好 Web 与服务器之间通信通道。

Flash 彻底退出还要两年时间,在这段时间里,通过如下框架也是可以适配 Flash 播放器。



△ H5P2P + FlashPlayer示意图

树状、网状:P2P 的选型

我们总结一下过去若干年的 P2P 直播,主要有这样的一些特征,要么树型结构,要么网状结构,要么树型和网状融合起来。

Tree:树型Mesh:网状Tree + Mesh:树型 +网状

树状结构是最传统的 P2P 直播,把播放节点分成很多个层次,呈现一棵直播树的形态。直播流通过 RTMP 推送到 CDN 服务器上,然后数据一层层地往下推:数据先往第一层节点发,第一层节点收到了之后再发给第二层节点,第二层节点再发给第三层节点,以此类推,逐层往下发。



△ 树状 P2P 直播示意图

当播放人数变多,P2P 直播的节点层级也变得很大,最多时会有十几层。这导致它的延时非常大,少则 30 秒,多则达到几分钟的延迟。这种延时水平,在目前的游戏直播、秀场直播等直播应用场景里面是无法应用的。

另一方面,P2P 节点很容易出现退出等不稳定情况,比如用户关闭设备、退出程序等。P2P 直播树有一个节点挂掉,它下面的子树下的所有节点都会受到影响。这也意味着 P2P 直播树不稳定。

大家对传统的 P2P 直播树做一些改进。比如节点只是从多个上层节点拿数据,避免子树的不稳定;节点不只是从上层拿数据,同层之间也可以拿数据,这就是在同层之中引入网状的结构了。



△ 网状 P2P 直播示意图

FlashP2P 事实上就抛弃了树的概念,直接用一个网状的概念。数据流一到播放节点,直接就开始在节点之间互相传输。这个类型网状 P2P 网络。

用 WebRTC 来做 P2P 的 Peer5 采用的是网状 P2P 网络。Streamroot 的解决方案也是网状结构。

高延迟:树状、网状 P2P 的困扰

相比树状 P2P 网络,网状 P2P 网络的优势是比较稳定,因为节点之间能够互传数据。

树状和网状 P2P 网络有两个共同特点,其中一个就是延时大,数据进来之后要经过好多中转才能到最后的播放节点。



树状和网状 P2P 网络另一个特点:分享率不高。为什么呢?家庭带宽上行、下行不对等限制了 P2P 网络的性能。下行如果有 20M,上行一般只有 2 到 4M 左右。在传统P2P网络里,播放端下载到数据后分享一部分给别人, 也就是说只有在播放的时候才能给别人传输数据,即数据只在播放节点之间互传。

我们设想一下,总共有 1000 人在播放,直播流码率是 2M 的话,要让这个直播能够百分之百通过 P2P 网络跑起来,则平均每个播放端必须提供 2M 上行带宽资源。在目前的接入网环境下,这是比较困难的。

再假如直播流码率达到了 3M,有 1000 人并发观看,并且平均每个播放端能提供 2M 有上行带宽。累加起来的播放带宽有 3G,但是这 1000 个播放终端总供应带宽上限是 2G,即使每个播放端全部供应数据,而且连接质量非常高的话,也存在 1G 的差额。这 1G 的数据,就需要到 CDN 边缘节点去补。

上行带宽的不足是导致了传统 P2P 网络的分享率不高的一个原因。

又拍云 PrismCDN

又拍云做 PrismCDN 这个产品,主要有三个要求:

第一,把体验做好;

第二,降低成本;

第三,要易使用。

我们先来看一下又拍云 PrismCDN 所取得的成绩,一项项分析 PrismCDN 在好体验、低成本、易使用三方面是否达标。

PrismCDN 一开始做 SDK P2P,在体验好、低成本上做得比较到位,但在“易使用”上不够优秀。所以我们研发了 WebP2P 功能。



△ 又拍云 PrismCDN WebP2P

易使用:无插件、免 SDK、易回滚

SDK 要嵌入到客户的 App 里面去,客户会担心三个问题:

SDK 的稳定性;SDK 升级的时候,客户需要重新发布新的App版本;SDK 部署之后,难回滚。

又拍云 PrismCDN 团队设计 WebP2P 的时候,集中解决了“易使用”这个难题。

WebP2P 没有插件,也没有 SDK,只是 JS 而已;发生异常只需切一下老版本就好,不需要像 App 那样重新发布一个新版本,客户的开发成本下降,风险也降低了。

体验好:流畅度高、延时低、秒开

我们把 P2P 直播的体验分为“流畅度”“延时低”“秒开”几个指标。

流畅度:尽量不要卡顿,把卡顿率降下来,我们做到了 99.9%;。延时低:延时在 3 秒水平,和 CDN 直播的延时是相同的。秀场直播或者游戏直播,有一定的互动,延时一定控制在几秒之内,用户才可以接受。秒开:首屏秒开,用户一点进去的时候,直播画面就能启动起来;当然首屏时间和 P2P 没什么关系。

低成本:

又拍云 PrismCDN 90%的流量来自于 P2P 雾节点,只需要 CDN 边缘节点补充 10% 的流量。雾节点的成本大大低于 CDN 边缘节点的成本,P2P 分享率高,就意味着整体成本下降,对客户来说非常划算。

PrismCDN 架构解析

后面我会分析我们是如何做到这三点的。在这之前,先了解一下又拍云 PrismCDN 的架构。



△ 又拍云 PrismCDN 架构示意图

三角形里是 CDN 服务器。熟悉 CDN 的人都知道它有三层的架构:中心节点、区域节点、边缘结点。

我们在做 PrismCDN 这张 P2P-CDN 网络时,引入了“雾节点”。雾节点包括 OTT 机顶盒、路由器、APP 等,运行 WebRTC 的网页也是可以充当雾节点。我们会把数据从 CDN 边缘节点再次下沉,下沉到雾节点上。最后通过雾节点向客户提供数据。

这个架构把 CDN 网络的三层模型变成了四层模型。第四层就是布置在用户边上的雾节点,在离用户最近的边缘计算资源里面。

第五排是最终用户端。示意图里把用户端要拆分为 WebRTC、Flash、App 几个模块,本质上是同一个。

放大 CDN 带宽的雾节点

我们重点看一下“雾节点”是怎么回事。CDN 网络的边缘节点,统一看成一个 CDN 服务器。CDN 服务器会推送 1/20 的数据流到雾节点上。雾节点会和十几、二十个播放端相连,直接把这 1/20 数据流转发到各个播放端。



△ 又拍云 PrismCDN “雾节点”运行示意图

我们可以计算一下。假设 CDN 推送 2M 的直播流,到了雾节点这边就是 100K 的数据,假设雾节点转发到 10 个播放端,这 10 个播放端就得到了 1M 的数据。这 1M 数据对于播放端来讲都是有效数据,即 CDN 的 100K 宽带,通过一个雾节点使播放端得到了 1M 的带宽,这起到了放大 CDN 带宽的作用,相当于把 CDN 带宽放大了 10倍。

哪些设备能成为雾节点呢?以路由器举个例子。路由器只要集成一个 PrismCDN 雾节点的模块,在这个模块实现 WebRTC 需要的协议,比如 ICE、STUN 用于穿透的协议、DataChannel、DTLS、SCTP 等 P2P 连接的协议。有了这些协议就可以实现雾节点之间以及雾节点与 Web、 APP 之间的通讯。

同理,在播放的 App 也可以成为雾节点,只要它支持 WebRTC 协议并且保持在线。App 可以根据客户的需求来配置是否作雾节点。如果说客户需要提供转发,我们就可以把这个模块运行起来。

播放 Web 也可以作雾节点。这个比较好理解,本质上是两个 Web 之间传数据。同理,我们也可以通过根据客户的需求,配置 Web 要不要作雾节点转发数据。

PrismCDN 网络运作介绍

通过 PrismCDN 网络实现 P2P 直播,具体讲起来还是有点复杂的,我们一步步来介绍。

第一步,先是直播源把一个 RTMP 流推到 CDN 网络的中心节点上。CDN 中心节点对这个源进行做切块,比如 20K 大小的 Block,于是直播流就变成了一个个 Block 的序列。在 CDN 网络里先把 Block 序列逐层发送到边缘节点上。

在 CDN 边缘节点到雾节点之间,就不是传输一个 Block 了,而是传输 Block 里面的 1/20。我们通过一些算法从 Block 里面抽取 1/20 的数据推送到雾节点上面。雾节点再把 1/20 的数据转发给和它相连的若干个播放节点。

一个雾节点会连接很多个播放节点,一个播放节点也会和很多个雾节点相连,并从这些雾节点处收数据。播放节点从每个雾节点获取的数据,就是CDN边缘节点推送到雾节点的 Block 的 1/20 子数据流。

这就是 PrismCDN 网络 P2P 部分的工作逻辑。

如果说 P2P 某些节点是丢包了,或者是掉线了,那么播放节点可以直接连接 CDN 边缘节点,把丢失或者需要补充的数据给拉回来。最终播放节点能够把来自雾节点和 CDN 边缘节点的数据数据组合还原出来原始的流,然后再通过转封装成 MP4 或者 FLV 等格式之后,喂给相应的播放器。

低延迟的奥秘:扁平化模型

传统 P2P 最大的问题就是延时很高,不论树型的直播方案,还是 Peer5、Streamroot 等网状型直播方案,延时都非常高。

PrismCDN 网络是怎么做到低延时的呢?这和我们的扁平化的模型有关。

CDN 服务器几乎同时把一个数据流的 1/20 子流推到很多雾节点,雾节点同时把数据推到了播放节点。整个过程中,数据路径非常短,它只是通过雾节点同时中转一下。

通过扁平化的方案,PrismCDN 把延时控制在了 3 秒以内,和传统 CDN 差不多,这个延时水平能够满足游戏直播、秀场直播、体育直播等多个直播场景。相比之下,传统 P2P 直播的延时有半分钟甚至 1 分钟之多。



△ PrismCDN 低延迟的奥秘:扁平化模型

高流畅的奥秘:雾节点智能选择、冗余链接

再来看看 PrismCDN 网络在高流畅方面是怎么做的。



△ PrismCDN 高流畅的奥秘:CDN 边缘节点补数据

从上面的介绍,我们知道一个播放节点的大部分数据是来自于雾节点。完全依赖雾节点,会出现数据缺失。遇上数据丢失,PrismCDN 会通过数据通道从 CDN 边缘节点拉取数据。这个模型就是 P2SP。

要做到流畅的话,要分两大块去考虑的:一块是资源;另一方面是技术,包括调度算法、回源算法等内容。

比如说在数据通道里面,我们就会有各种方式做尝试、做测试。又拍云 PrismCDN 团队在线上、在生产环境里面去做对比测试,发现用 UDP 来传数据要比 TCP 效果好很多,流畅度上面大概要高 5%。

在 WebP2P 里面,有两种补数据的方式:一种是要 WebSocket 去补数据,另外一种是用 WebRTC DataChannel 去补数据。我们在这两种方案里面进行 AB Testing。

资源不足的话,技术做得再好都没用。好比 CDN 网络,需要备充足的资源之后才能提供很好的服务。我们依赖于又拍云 CDN 网络在全国各地的服务器、CDN 节点资源,同时雾节点的资源也部署了 100 多万个。

雾节点智能选择

PrismCDN 有超百万规模的雾节点,雾节点的选择是非常重要的。

我们在雾节点、播放节点方面有几个心得:

智能选择雾节点雾节点、播放节点就近原则雾节点、播放节点相同 ISP 原则冗余链接,大数据分析雾节点质量

雾节点和播放节点,尽量匹配相同 ISP、相同区域进行对接。假设某个雾节点是使用上海电信的,我们尽量给他匹配上海电信的播放节点。因为跨地区、跨运营商的传输质量不太好。跨运营商的通信质量不大好,尤其是对 UDP 协议的支持质量。为了避免运营商之间的数据传输出现错误,PrismCDN 自写了一层去校验数据包是否正确。

我们还可以对雾节点的质量进行统计分析,做更好的匹配。

冗余链接

看完雾节点选择的优化,我们再看看连接的情况。又拍云 PrismCDM 的连接原则,概括一下就是:启用冗余 P2P 连接,根据节点质量调整冗余度,减少 CDN 回源量。

每个雾节点传输一个 Block 的 1/20 数据,按理说一个播放节点连接 20 个雾节点就可以了。实际上一个播放节点通常会多连接 1 到 2 个雾节点。因为雾节点毕竟是 P2P 节点,稳定性没有像 CDN 节点那么高,有时候会退出、会掉线、会丢包,必须给播放节点准备一些冗余连接。比如说播放节点连接了 21 个雾节点,某一个雾节点中断或者丢包了,没关系,播放节点已经收到 20 份数据了,还是能够组合、还原出原始数据。

同时可以根据实时的传输情况来调整播放节点的链接冗余度。如果传输都是稳定的,一个播放节点连 21 个雾节点就可以了。如果传输的抖动比较大,或者雾节点不太稳定,冗余链接数就放大一点。最终目的是播放节点需要的数据都能从雾节点收到,不需要启动 CDN 回源,不需要去 CDN 边缘节点拉取补充数据,这样流畅度就变得非常高。

CDN 的成本要高于 P2P,因此用冗余链接的方式减少 CDN 回源,除了保障流畅度,还可以降低成本。

低成本的奥秘:P2P 分享率高

最后看又拍云 PrismCDN 低成本的一些情况。

通过 PrismCDN,播放带宽由两部分组成:一部分是 CDN 带宽,一部分是 P2P 带宽。我们的原则就是,提高 P2P 雾节点的分享率:加大 P2P 带宽的比例,尽可能减少 CDN 带宽占比。

在传统 P2P 网络里,数据在播放节点之间互传,播放器会下载数据后分享一部分给别人。也就是说只有在播放的时候,节点才能给别人传输数据。

现在的家庭带宽都是上下不对称的,下行如果有 20M,上行一般只有 2 到 4M 左右。大致计算一下,如果是一个码率 3M 的直播流,有 1000 个并发观看,累加起来的播放带宽要达到 3G。那么这时候这 1000 个播放终端供应的带宽上限是 2G,即使每个人全部供应数据,连接非常高效率的话,也存在 1G 的差额。这 1G 的数据,就需要 CDN 边缘节点去补。

相比于传统的 P2P 来做的话,PrismCDN 引入了纯粹提供数据但不需要播放的设备,比如路由器、机顶盒、光猫等设备。这样就填补了上面所说的 1G 的差额。

刚才也提到了,冗余链接不仅能够保证流畅度,也可以提供低成本的优势。尽量从雾节点多传一点数据,减少通过 CDN 边缘节点拉取数据的概率。毕竟雾节点的成本比 CDN 低的多。雾节点的流量增多,CDN 边缘节点流量减少,整张 PrismCDN 网络的成本就会降下来。