B站直播中HLS和去中心化P2P的实际应用
Posted LiveVideoStack_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了B站直播中HLS和去中心化P2P的实际应用相关的知识,希望对你有一定的参考价值。
随着光纤入户的普及和电脑性能的不断提升,观众对直播的需求越来越高。常用的流媒体协议HLS虽已被广泛用于PC和手机终端的音视频服务,但在使用中仍然存在一些不足。我们邀请到哔哩哔哩弹幕视频网直播技术部的姜军老师,介绍基于HLS的直播P2P以及研发过程中他们遇到的挑战及未来规划。
文 / 姜军
整理 / LiveVideoStack
大家好,我是哔哩哔哩弹幕视频网直播技术部的姜军,今天主要介绍基于HLS的P2P。HLS是比较早的技术,全称是HTTP Live Streaming,字面意思是利用HTTP进行播放直播,在开发过程中或者是网络搭建过程中,它可以大限度利用以前静态文件的CDN服务,部署过程比较方便;但缺点是延时大,首帧加载慢。我们在工程化部署服务的时候会有各种方式来缓解问题。
前半部分介绍HLS的内容,后半部分介绍基于HLS的P2P。因为HLS是基于短文件的,一个个文件进行分片传输,所以比较容易开发基于HLS的P2P。
今天的分享分为六个方面——引言、HLS直播、HLS直播的优化、直播P2P、直播P2P的挑战、去中心化协作。
#01 引言
首先是引言部分。
目前用户对高清直播的需求越来越强烈,电脑性能的提升让以前卡顿的视频可以流畅播放,内容平台可以提供更高清的视频,发挥硬件性能,得到更好的观看体验。直播画质的提升对编解码器性能和宽带成本提出了更高的要求,画面和声音越清晰,需要传输的数据越多。目前网络成本一直处于很高的水平(按照带宽计算费用),如果为每个用户提供高质量内容,那带宽的成本是非常大的。
哔哩哔哩直播现在采用HLS传输和P2P相结合的方式,提升了服务器带宽的利用效率(本来一倍量的带宽给一倍量的人看,那么现在一倍量的带宽可以给两倍甚至三倍的人看,在相同的带宽压力下可以服务更多观众)。
哔哩哔哩现在可以将分享率(指上传下载比)只有100%的时候将节省率做到70%,这70%是用户量不论多少表现相似。
#02 HLS篇
首先向大家介绍前半部分——HLS。
2.1.什么是HLS——HTTP Live Streaming
HLS全称是HTTP Live Streaming,字面意思是用HTTP做直播,HLS有很多版本。大家见到比较多的是旧版本的HLS,也就是一个m3u8的文件其中包含很多小的TS文件的列表。其实m3u8这样的东西很多,从上一个年代就开始使用电脑的人比较熟知,因为那时的音乐播放器的文件列表格式是“.m3u”。m3u8其实是同样的,它作为播放列表,随着时间的推移里面的项越来越多,因为随着直播进行、内容总时长是不断增加的。随着新项的添加,旧项会被移除,和队列一样。HLS的播放列表里就会保持最后一小段时间内容的文件列表,于是客户端一边轮询m3u8文件的变化,一边下载小分片进行播放。
因为传统的MP4文件结构所限,所有的索引放在一起、所有的数据放在一起,播放的时候两者缺一不可,但得到完整数据之前无法拿到完整的索引。在这种情况下,传统MP4文件虽然可以做到边下边播,却无法实现直播。为了做到直播,MP4文件需要进行分段(0.5s或者1s为组),分完之后一边传给服务器,一边服务器传给用户这样进行直播。HLSv7是将分开后的数据块独立成小文件放在列表中,然后不断更新m3u8的播放列表。
左图是传统MP4。和分段MP4的不同,传统MP4文件是一个大的索引,数据块只有一大个;而分段MP4文件每一小块都有索引和与其对应的数据块。把这样一个分段MP4文件再切成一个个小文件之后,配上一个m3u8文件就可以变成HLS的流。
2.2.为什么用HLS
CDN部署更容易:HLS的CDN部署比较容易,因为它基于文件传输而不是长流传输,这样的话传统的静态文件CDN只要经过少量修改,对cache进行配置,就能够实现支持HLS直播。
清晰度的动态切换:因为HLS是一个个短文件而没有长流,因为长流比较难做清晰度切换的原因是从一个清晰度切到另一个清晰度时,我们难以知道刚才的位置所在,这种seek操作对服务器端开发难度比较大;但如果全是小文件的话,只要小文件能一个个在不同清晰度间对齐,那么切换清晰度就会很容易。
容易支持实时回看:在使用HLS的情况下,如果将分片文件的过期时间设置比较长,那么当用户进入直播间较迟、又想看早一些的内容,客户端就可以把旧的分片文件提供给该用户看。
原生支持移动版Safari:Safari和其它浏览器不同的是它在移动端没有Media Source Extension组件;也就是说如果不是Safari的video标签直接支持的流,那就无法播放。
原生支持H.265,AV1等新编码:HLS依托MP4结构,可以原生支持H.265,AV1,而不是通过一些民间的hack协议去做的,目前线上用的最多的FLV,因为各个新协议都是通过不停地hack来追加的,所以各种工具系统的原生支持比较差,比如我想要Flv支持H.265,发现现有的软件系统都不支持,那就必须一个个改造过去;如果不同的厂商hack方式不同,那么这些系统之间就无法互相集成。
2.3.HLS直播的优化
我们主要从三个方面进行优化:
使用fMP4替代TS:大部分浏览器不能原生支持TS流,但能够支持CMAF的长流,所以我们就根据新HLS协议,把里面的TS换成HLSv7里CMAF的格式,这样数据拿下来之后直接送给浏览器,浏览器可以直接播放,中间不需要javascript脚本进行大规模处理,可以减少浏览器的CPU消耗,对用户来说电脑不容易卡。
非关键帧切割:关键帧是用来起播的,起播之后,剩下的数据可以不以关键帧为边界往浏览器里送,这样切割长度就可以比较小(比如0.5s或1s一个片),传输延迟也可以降低。以前的HLS,因为每个分片要从关键帧开始,不然会黑屏;如果能支持非关键帧切割,延迟问题就能随之解决。
多文件合并:分片文件可以边下边播,刚才看到的左图(ppt第7页),你会发现图片右边划分的还是init分片、001、002,实际上在这里面001还可以细分为更小分片(001.2、001.3),这种更小的分片可以作为同一个文件传输,也就是说一个文件里可能不只有一个分片(指一个moof和mdat的组合),对于这种文件来说就可以边下边播(比如一个文件为1s,可以分为三个0.33s的小分片,那么文件只要下载前1/3就可以直接送给浏览器,浏览器开始播放画面),可以提高用户体验:因为在文件下好之前,画面就可以全部出来,不会出现用户进入直播间很久却没加载出画面的情况。
#03 P2P篇
我们做HLS的一个主要目的实际上是开发P2P。因为HLS小文件分片的传输方式是比较适合开发P2P的:小文件是天然切割好的分片单位,也就是可以以文件为单位在用户之间交换数据。
P2P篇分为三部分来介绍:直播P2P、直播P2P的挑战,最关键的去中心化协作。
3.1.直播P2P
P2P实际上流程比较简单,它跟传统直播比起来实际就多了一个用户之间的数据交换,P2P相关的逻辑在很多年之前就一直存在,从BitTorrent到电骡都是基于P2P进行数据传输的,相关概念这里我直接套用当年的解释。比如P2P过程中网络中的Peer概念,它代表整个P2P网络的对等节点,他们之间会互相传输数据;提供数据和接受数据的角色分别为Seeder和Leecher,他们都可以算作Peer。在我们设计的P2P网络中,Seeder和Leecher是混合的,也就是一个用户既做Seeder又做Leecher,然后互相交换数据。
分享率是指上行和下载的比率,在以前的BT软件中这个概念是很常见的。BT软件有一个功能是数据下载完成后,还要继续做一段时间的种子才能停止,停止条件是分享率达到一个值(比如下载1G数据,分享率设置为1.5,意味着上行量到1.5G数据时就可以停止任务)。
我们现在是CDN和P2P混合使用,于是有了“节省率”这个概念,字面上是P2P下载占总下载比例的多少,比如P2P占了70%数据量,CDN占了30%,那么节省率就是70%。
P2P下载流程如图所示,从每个分片开始下载到交付数据给播放器,其中包括了三个节点,这些节点有的可以跳过。一开始下载种子数据,种子数据是指直接从CDN获取、然后提供给其他用户的数据,举一个例子,比如我现在有4个用户,他们互相组成小网络,每个用户都可以从服务器中下载1/4部分,当用户下载完4个数据之后,服务器吐出的上行量实际上只有一倍,一个文件吐了4次每次四分之一,只是QPS会多一些。用户拿到各自数据之后,之间互相交换后就可以拥有完整数据。也有一种意外情况,4个用户中有人下载了与别人相同的分片,这就导致整个网络中有数据缺失,那么就要在P2P数据交换完成之后,从服务器补充缺失数据,最后交付给浏览器。
因为这套P2P基于纯HLS,所以服务器不需要特殊适配。整个流程就是“下载种子数据、交换、下载缺失数据、交付”。标准的HLS完全可以满足这套流程的正常运行。而一个片段文件的单个分片的下载,依靠HTTP的Range即可满足,所以文件CDN页不需要专门改造,正常可用地支持静态文件下载,能支持Range,就能为这套P2P方案提供服务。
无需要可不下载种子数据。刚才举例说的4个用户交换数据的情况是因为只有4个用户。但如果有六个用户,就可以出现这样一种情况:6个用户中有的人不从CDN下载数据,只从P2P网络下载,我们现在这套协议支持数据从P2P网络来再回到P2P网络里去,整个过程是帮别人倒手数据,但自己手头上也就有这部分数据了,这样效率比较高。
P2P交换数据弹性时长。P2P时间过短,分享率无法上升,因为用户之间交换数据需要一定时间。如果用户播放器缓冲的数据比较多,可以给P2P留有更多时间进行交换,这样时长可以调整,在保证分享率和节省率的条件下,做到用户体验较好,延时不会变长。
数据完整时不需要补缺。图中下载缺失数据的节点,在当获取到完整数据时可以直接跳过。
3.2.直播P2P的挑战
P2P的挑战主要有三方面:
实时性要求高。因为现在做的是直播,而不是下载完成后观看。BT用户可以把文件挂在后台慢慢下载一两天,完成后再观看。直播如果是下载完成再观看的话就丢失了它本身的意义。实时性要求高是指下载速度必须大于播放器消费速度。
直播间进出频繁。用户进出直播间频繁会导致P2P网络需要不断调整。刚才说到我们的这套流程和我在网上看到的别人的方案不太一样是指,网上的流程是把不同用户进行分组,组内用户互相连接、根据服务器调度的任务进行计划的数据交换;那么如果大量用户频繁进出直播间,分组变化剧烈,还要考虑用户间的连接成功率,调度是极大的挑战,不易达到稳定态,P2P的节省率就会受到影响。
网络环境复杂。还是刚才的例子,有4个人连成小网络,但这4个人的上行下载速度和数据传输速度不一定相同。可能A到B网络传输好,C到D网络传输差,但B到C又很好,这都是不一定的,还有可能是A到B差,但是B到A快。网络环境复杂,由服务器分配任务,决定谁应该下载什么,给谁传输数据,那么服务器这边就会有非常多每个用户的状态数据,还要随着用户实时变化,如此大量数据下进行调度,这个难度非常大。
我们的P2P协议是基于WebRTC DataChannel的传输。DataChannel非常灵活,不需要视频通道那样传输完整视频数据。意味着每个用户只要有上行带宽,离设定的“限制值”还有一定额度,就可以“供血”。因为用的是RTC标准协议,这套方案除了在浏览器里跑之外,还可以在手机端或是电脑的原生客户端里跑。这样的好处是,手机和电脑情况不同,如果手机只能与手机互相连接,手机的网络稳定程度又通常比较差,那手机端的节省率会比较差;如果能够将两个网络利用在一起,允许手机和电脑互相连接,就可以提高网络的运行效率。
P2P协议是设计成异步、重叠的实现。类似一个传输通道可以并发多个正在进行的传输请求存在,举个例子有点像HTTP/2,P2P协议是发出一个请求后不用等到回复就可以发送下一个。
Peer自发查询+下载,抢占+重试的实现。“自发查询”是指用户下载数据时不需要知道谁有数据,而是向大家广播查询下载进度,等确认对方持有想要的数据后,才发起下载。这不是由服务器调度的,而是用户之间自己调度。“抢占+重试”是指下载数据时,假设一个文件分为十个块,现在要下载第一个块就要发送请求下载,这时第一个块相当于一个任务。但用户情况多变,发送请求后可能断开连接,那么第一个块此时下载失败,就要再找其他人尝试。“抢占”就是广播查询时,谁先返回说有第一个块,就先找谁下载。这样才能够保证较高的传输效率。如果我先拿到第一个块的数据,就可以再把它给其他人,进行二级传递、三级传递,提高利用率。
上传均匀分布。现在设定为每一个用户上行不能大于下载,比如下载了1兆数据,上行量不能大于1兆。上行太高的话,会影响正常上网,使用户网络卡,影响其它软件的使用,另外如果我是用户看到上下行速度不对等,下载数据少,上传数据多,心里会不愉快,就会进行投诉,这也是不好的影响。
3.3.分布式调度
现在P2P的任务分配不需要中心服务器进行任务下发。虽然用户会连一个服务器(因为WebRTC整个连接流程必须需要服务器参与)只是在服务器参与连接建立阶段之后,不进行任务下发。连接后所做的事情由用户而不是服务器决定。
一边传输一边调整。回到4个用户连成的小网络的例子,他们从服务器下载4个不同的部分并进行数据交换时,传输效率最高。极端来说,P2P是服务器只要给一倍的数据就可以满足所有直播间所有用户的需求。这当然几乎不可能实现。我们需要使用调整算法尽可能使服务器数据能够少传输一点。在有P2P参与的情况下,服务器传输的数据里重复的越少,总数据量也就越少;如果传输重复数据,服务器的带宽利用率就会低。一边传输一边调整的“调整”是指4个用户可以下载文件的不同部分,但因为用户的进进出出,断开之后可能有新用户进来,新用户进来之后不知道做什么,我们就需要一种算法来帮助新用户决定下载文件的哪个部分。
我们采取的算法就是市场调整算法。
这是市场供求关系的仿制,把每个文件分成4份,每份独立计算节省率与分享率,来计算供需关系。当供应数据方供应量有限时,作为用户就会发现在P2P网络中下载数据非常困难,此时我就会认为市场中这个数据块很紧缺,按照调度算法现在应该补缺,比如用户发现某个范围数据无法从P2P网络获取,那他就会变为从服务器中下载数据然后供给P2P网络解决紧缺问题。也有供大于求的情况(服务器重复吐数据),比如有很多用户直接从服务器下载第一个分片,那这样的话其实意味着分享率很低:因为大家都要求服务器给同样的数据,而这块数据因为下载的人多,通过P2P网络来满足是更优的。供大于求的情况下,有的用户就会由SDK内部算法,变为这部分数据就不从CDN下载,而是从别人那边获取的状态。
根据供求关系做实时调整,最后收敛到供需平衡。变为正好有这么多用户下载数据传输给别人,而传输的数据正好是别人所需要的,不存在多下载或缺数据的情况。
现在这套算法在网上跑的时候,(曲线图显示跑出线上实际数据的实测效果)曲线代表节省率,可以看到比较接近75%,随着用户数上升下降,虚线波动率不会很大,横轴的几个凹陷是在凌晨4点左右,那时用户量太少不在考虑范围内,我们主要提升用户量大时的节省率。图中可发现用户量急剧上升或下降的时候,节省率依然是保持稳定的,图中尖尖的几条线代表带宽(同时也就是人数的变化趋势),随着带宽变化,节省率变化也不太大。
可以看出节省率对人数变化不敏感,因为内部是通过市场调节算法收敛到平衡。然后是可以适应复杂网络环境,这套供求关系在用户手上有数据时分为两种情况,一个是上行带宽好,数据能够发送出去,另一个是上行带宽不好,数据不能发送出去。如果由服务器调节,服务器还要考虑用户带宽的情况,调节算法会非常复杂;通过自适应调节方式,当用户手上有数据但不能发送时,其他人会认为这块数据还是紧缺的。
3.4.其他相关结果
其他相关结果有两方面。
第一是实时参数下发,市场调节算法中有许多小参数进行控制,如果能够看到参数的实时调整结果,调整效率会比较高,调整起来也会比较方便,最终拿到一套最优的参数集合。
第二是QPS,之前提到用户会使用Range请求文件下载。在我们上线之前最担心的是用Range请求服务端会导致服务端的QPS非常高,但现在跑起来看效果发现有的P2P网络传输的QPS与关闭P2P几乎等同,在90%和110%之间来回波动,90%是指开着P2P时QPS反而更低,而110%是指开着P2P,QPS会高10%左右。目前带宽最高线上数据跑起来可以达到110%,平时在100%左右波动,凌晨节省率比较低的同时QPS也比较低。也就是说在这套系统下,可以认为QPS和纯跑HLS几乎等同。
3.5.未来研究方向
现在的算法虽然已经在线上跑了,但还有许多方面需要进行优化:
缩短算法收敛耗时:算法收敛内部测试需要大概30s-60s达到供需平衡,虽然看起来时间短,但在用户进出频繁情况下,网络很难达到最优情况,所以分享率一直在70%波动。我认为有优化的空间是之前有一个频道直播了探月卫星发射,和娱乐直播不同的是,观众进入直播间后会一直等到卫星发射完成才会退出,也就是用户在直播间的时间会很长。算法跑到了收敛,那次的分享率达到了80%。但用户进出频繁是常态,还是需要优化算法收敛时间从而达到更好的效果。
缩短P2P环节弹性时长:刚才说道,播放器的缓冲时间长短可以调节P2P的使用时间,虽然可以提高P2P的分享率和节省率,但是坏处是P2P数据交换节点的耗时越长,用户看到的数据越延迟,这会降低用户的体验,要把延迟降到接近不开P2P的情况才是更好的方向。
优化数据块路由:是指数据块通过什么方式和线路从服务器到用户端。现在整个通过“抢占”来传输数据,导致有的用户一直处于“饥饿”状态,如果服务器能够干涉一点,通过算法将尾端用户拉到前面,这样会提升网络分享率。
提升分配效率,下调分享率限制:虽然我们的分享率已经调整为上传不大于下载,但是用户在任务管理器或是网络监测器中发现数据在跑的其实还会有点不愉快,如果再压一压上行速率,也可以提升用户体验。体验不一定只包括网页是否流畅,业务是否可用,可能还包括用户在各个监控看到的服务跑起来占用的资源。
以上是我分享的内容,谢谢!
详情请扫描图中二维码或点击阅读原文了解大会更多信息。
以上是关于B站直播中HLS和去中心化P2P的实际应用的主要内容,如果未能解决你的问题,请参考以下文章