摘要
WebRTC把实时流媒体和P2P等能力带入了Web前端,开发者只需编写简单的JavaScript程序即可开发出丰富的实时多媒体应用。本次大会想跟大家分享我们对WebRTC的一些实践心得,以及如何利用WebRTC的数据通道来做P2P流媒体。最后介绍我们如何设计一个低延迟、高带宽利用率的P2P流媒体算法。
WebRTC的诞生背景
我们知道现在实时视频通信很普遍,基于FaceTime和Skype等视频通话工具,用户可以很方便地与他人进行视频对话。开发者们为了将用户体验优化到极致,通过大量的技术手段保障视频质量,比如减少丢包、断网恢复、即时响应用户网络变化等等。实时音视频通信对开发者的技术要求比较高,而且专利持有公司向开发者征收授权费,并构筑起巨大的技术壁垒。另一方面,对用户来说,需要去额外安装相应的插件或者应用程序,降低了用户体验,而且还有被捆绑流氓软件的风险。这时候一种叫WebRTC的技术应运而生了。
在讲WebRTC之前,我们先回顾一下Web通信的演化历史。在AJAX出现之前,也就是05年之前,如果需要更新内容,必须重载整个网页页面。AJAX出现之后,通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。但AJAX不能与服务器进行双工通信,因此服务器无法主动推消息给浏览器,只能通过浏览器进行轮询。Websocket的出现使这个局面得到改观,浏览器与服务器能进行全双工通信。不管是AJAX还是Websocket,都需要将数据发送给服务端。为了在两个用户间传送数据,开发者需要购买服务器网络,这方面的成本是非常庞大的。由谷歌支持的一项新技术——WebRTC彻底改变了这个局面。WebRTC是Web Real-Time Communication的缩写,实现了浏览器之间直接的实时通讯,而不再需要服务器中转,谷歌致力于让其成为HTML5的标准之一,目前大部分浏览器也已经支持。
WebRTC与P2P的结合
12年谷歌的chrome浏览器正式原生支持WebRTC,web开发者只需要几行javascript代码就可以开发出丰富的实时多媒体应用,而用户也无需安装插件,直接打开浏览器就可以与对方实时聊天。这时候有些嗅觉敏锐的开发者开始利用WebRTC的数据通道技术做P2P流媒体,例如国外一家公司叫做peer5。我们公司的创始人Alan在腾讯工作的时候也投入到这方面的研究,但失望的发现用WebRTC做P2P流媒体还有一些问题难以解决,比如用户在线的时间并不稳定,当用户关闭页面,WebRTC的数据通道也就关闭了。随后在13年和14年,Firefox和Opera也相继宣布支持WebRTC。这时Alan提出一个大胆的设想,既然浏览器做种不稳定,那么把相同的协议实现在路由器和NAS中呢?我们都知道路由器是24小时开启的,但大部分时间是处于闲置状态,如果能把这些计算能力和网络带宽利用起来,这样相当于千家万户都是节点,你的邻居甚至你自己也许就在为你看视频提供加速,想想都是很酷的事情!因此我们提出了众包CDN的概念,并且申请了专利。15年,腾讯的X5浏览器内核和微信也提供了支持,同年,我们梨享计算也正式宣布成立。
可能大家会有疑问,WebRTC将来真的会成为一种主流技术吗?我们用事实说话,看看各大浏览器的支持情况就知道了。从图中可以看出,大部分浏览器都已支持WebRTC,包括chrome、firefox和opera,微软的edge浏览器部分支持WebRTC。另外,苹果也在近期的WWDC大会上宣布safari11支持WebRTC。未来基于WebRTC的应用将越来越多,这是可以肯定的。
WebRTC媒体会话原理
我们假设现在有两个浏览器A和B要建立WebRTC对等连接,对等连接就是两个Web浏览器之间的直接媒体连接,如果A要主动联系B,需要先通过HTTP向信令服务器发送一个SDP,SDP可以理解为一个电脑名片,全称是Session Description Protocol,会话描述协议,用于描述对等连接的媒体特征。那么信令服务器又是什么呢?它就像一个红娘,帮两个互相不认识的人牵线。浏览器A发过来的SDP叫做offer,信令服务器将其传给浏览器B,后者收到后回应一个SDP对象,叫做answer,也通过信令服务器中转给A。交换完SDP后,两个对等端就开始尝试ICE打洞,打洞成功后开始协商密钥,之后就可以开始安全的媒体或数据会话了。
ICE打洞原理
由于IPv4提供的IP资源有限,IPv6还没有推广开来,大部分网络设备还处于内网中,需要通过NAT设备来与外部internet连接。NAT全称Network Address Translation,网络地址转换,装有NAT软件的路由器叫做NAT路由器,它至少有一个有效的外部全球IP地址。这样,所有使用本地地址的主机在和外界通信时,都要在NAT路由器上将其本地地址转换成全球IP地址,才能和因特网连接。当两个对等端处于不同的局域网中时,需要先知道对方的公网IP和端口。这时候可以先向STUN服务器发送测试数据包,后者做出响应,指示其在测试数据包中监测到的IP地址,此地址将成为潜在的候选地址返回。拿到候选地址的浏览器将其通过信令服务器发送给对等端,对等端也进行同样的操作,之后双方用所有得到的候选地址尝试连接,如果都没有成功的情况下,会用TURN服务器来作为中转服务器,TURN服务器是在所有替代方案都无效的情况下才有采取的,因为成本比较高昂。为了加速通话建立时间,有一个叫trickle ice的方案,其思想是客户端一边收集candidate一边发送给对方,比如local candidate 不需要通过stun获取直接就可以发起,这降低了了连通性检测完成的时间。
WebRTC数据通道
接下来介绍一个比较重要的概念——WebRTC data channel。我们基于WebRTC来做P2P流媒体,实际上就是用的data channel能力。那么data channel到底是什么呢?虽然有关WebRTC的宣传主要侧重于它对于实时音视频通讯的支持,但设计师一直都希望它也支持实时数据传输。相比Websocket和HTTP,数据通道支持流量大、延迟低的连接,具有稳定可靠等优点。而且data channel的接口和websocket一样,也是通过send来发送数据,通过ommessage来接收数据。那么如何对data channel数据传输的可靠性进行控制呢?通过刚才所讲的dataChannelOptions这个javascript对象,可以让data channel在UDP或者TCP的优势之间进行切换,比如让数据传输得更加稳定可靠,或者传输得更快。其中有几个比较重要的字段:ordered:设置数据的接受是否需要按照发送时的顺序,maxRetransmitTime:设置数据发送失败时,多久重新发送,maxRetransmits:设置数据发送失败时,最多重发次数。主要是配置ordered,当设置为true时数据通道表现更像TCP,false时表现更像UDP。
梨享计算与WebRTC
此外,我们公司一直对WebRTC标准化保持着关注并贡献力量。在去年,我们在研发过程中发现有一个第三方的webrtc协议栈能与chrome浏览器进行通讯,但无法与firefox通讯,通过对比SDP发现firefox有一处实现与标准规范不一致。于是我们与firefox开发团队取得联系,提交了我们的修改建议,最初他们认为没有问题,但最终还是采纳了我们的建议,对sdp进行了修改。这也算是我们对推进webrtc标准化做出的一点点贡献。另外,我们也一直与腾讯浏览器内核团队保持着联系,争取WebRTC技术以及本次分享的上层的P2P-CDN加速协议得到全面的支持。
WebRTC与P2P流媒体
把WebRTC的data channel搞清楚后,我们就可以用用它来做P2P流媒体了。这方面已经有国外大神开发的知名开源项目:WebTorrent,在github上有1万多颗星。WebTorrent是一个开源的基于WebRTC 和BT协议的js框架,完全用javascript编写,可以同时运行于 Node.js 和浏览器,由于基于WebRTC,因此WebTorrent不需要安装任何插件,就可以跑在浏览器上。同时支持Chrome, Firefox 和 Opera浏览器。但是由于是基于BT协议,所以是一种pull-based的算法,这种算法是一种随机抓取的策略,随机抓取其它节点的buffer,但这样会存在一个问题:抓取的buffer不一定是目前需要的,也不一定是其他节点需要的,而且还会浪费下行带宽和其它节点的上行带宽,因此同时造成了“带宽饥饿”和“内容饥饿”问题。下面介绍一种改进版的pull-based算法——FirstAid算法。FirstAid是基于窗口滑动的,每隔一段时间触发一次窗口滑动,每个窗口又可以分成三段:urgent、normal和prefetch,urgent顾名思义,是离播放时间最近的buffer,所以优先级别最高,normal和prefetch优先级递减。当父节点为子节点传输buffer时,会优先满足urgent级别的要求,而暂停normal级别的,所以最紧迫的需求会优先得到满足,当子节点的urgent需求得到满足后,需要回过头来弥补他的竞争对手的需求,以达到一种互惠互利的状态。和刚才pull-based算法思想截然相反的是push-based算法,其中比较有代表性的是FashMesh算法,由港科大的学者提出来的一种P2P算法。FashMesh是基于一种叫Streaming Mesh的算法,将源节点的数据流分成多个子流,通过多棵生成树构成mesh来源源不断的传输给子节点,这种算法的优势是延迟低,带宽利用率高。Fast Mesh还可以根据每个子节点的上行带宽来动态的调整网络拓扑结构,让上行带宽大的节点更加接近源节点,从而充分利用网络的现有能力。根据一项对比试验,FastMesh可能是目前众多P2P算法中效果最好的。但这个算法也有缺点,当节点进入或离开网络时,都需要重新调整拓扑结构,因此不适合节点变化较大的情况。
我们自行研发的算法——Push-Pull算法则综合了push-based和pull-based两种算法的优势,用pull的方式从父节点获取优先级最高的buffer,由父节点以push的方式为其提供后续的buffer。另外,我们的算法混合HTTP、HTTPS、WebRTC、Websocket等多种协议,在优先保证用户体验的前提下最大化P2P率。经过测试,Push-Pull算法具备低延迟、高带宽利用率、高P2P率、对网络拓扑结构变化鲁棒性强等优势。
PearPlayer
PearPlayer(梨享播放器,github地址:https://github.com/PearInc/PearPlayer.js) 是完全用JavaScript写的开源HTML5流媒体播放框架,实现了融合HTTP(包含HTTPS、HTTP2)、WebRTC的多协议、多源、低延迟、高带宽利用率的无插件Web端流媒体加速能力。基于H5的MSE技术(Media Source Extension)将来自多个源节点的Buffer分块喂给播放器,再加上精心设计的算法来达到最优的调度策略及对各种异常情况的处理,Pear Player能在保证用户流畅视频体验的前提下最大化P2P率。
集成我们的PearPlayer.js也非常简单,只需要短短几行代码,把我们的js文件引入到script标签中,并把video的id还有token作为参数传给我们提供的函数中即可。Demo演示地址:https://qq.webrtc.win/watch,以下是demo截图。
除了播放器外,我们还开发了支持多协议、多源、混合P2P-CDN的下载器PearDownloader,可用于高清图、压缩包、软件发布或升级包、音乐、文档等大文件下载或在线服务的场景(github地址:https://github.com/PearInc/PearDownloader.js),Demo演示地址:https://qq.webrtc.win/download。
雾计算
最后,讲一下雾计算有关的内容。雾计算与云计算有什么区别呢?云在天空飘浮,高高在上,遥不可及;数据中心距离终端用户较远,用户消息需要经过若干跳才能够到达。而雾是贴近地面的云,是现实可及,就在你我身边。雾计算并非由性能强大的服务器组成,而是由性能较弱、更为分散但离用户更近的各类计算设备组成,例如智能路由器、网络存储设备等。雾能够弥补云的不足,并和云相互配合,协同工作。我们Pear公司一直在践行雾计算的理念,通过与国内知名的路由器、NAS厂商合作,我们拥有海量可持续稳定提供服务的节点。大部分带宽、存储、计算资源通过众包方式收集自终端用户稳定在线的边缘设备,服务能力覆盖全部地域、所有运营商、每处网络边缘。我们自研的调度系统可以动态、实时的感知和调度,让数据传输距离尽可能接近“零跳”。
相对于传统的模式,我们可以说是站在共享经济的风口上。我们知道传统的CDN厂商会先以批发价从ISP买进带宽,然后再以零售价卖给CP,CP买入带宽后进行内容分发,为终端用户提供CDN服务。我们与硬件厂商合作,在其设备中植入我们的软件,从而在千家万户拥有了分布广泛的节点。CP厂商和传统CDN厂商从我们这里买入带宽,我们将其内容分发到各个节点中,持有设备的用户在提高其计算资源和带宽资源的同时,也会得到我们的返利,BGP机房、ISP骨干网的压力也得以缓解,从而实现多赢局面。