图为:芒果TV CDN研发总监刘维
芒果TV CDN研发主要负责芒果TV点播、直播CDN的建设。现在主流的直播平台主要包括互动性平台,对业务的要求是低延时和流畅性,在保障这两个前提的基础上再去强调清晰度。芒果TV主要有两大需求方向:一个是对于电视台类的传统节目类的频道直播,还有一个就是大型的活动性直播,包括综艺、晚会等。
目前直播平台面临很多技术挑战,首先是视频编码,264是为了覆盖兼容性,265各个平台基本也都在使用,265主要是为了解决清晰度和节约带宽的问题,在音频上AAC是比较主流的,芒果TV也使用了EAC3,是为了解决多声道和高品质的问题,因为像《歌手》类唱歌型比赛对音频的要求比较高,封装一般主流网站是FLV流和HLS,但是芒果TV多了一个MPEG-TS,因此负载比较大,从视频编码格式、音频编码格式再乘以封装格式,所输出的并发流的路数非常多,终端覆盖,基本上移动端、网页端,PC端,芒果TV多一个重点的就是电视端,电视端带来的问题,就是它有很多的7×24频道直播,频道直播会对保障要求更过,频道直播还要求时移和回看功能,在直播平台,包括点播功能,从上面来看,整体的技术需求还是比较复杂的。
面对这些技术需求,芒果TV实行一些关键技术,来解决这些问题,一是高可用网站,还有无缝切流,最后一个是边缘同步切片。高可用源站,整个信号的流程是从信源开始,信源包括卫星,主要用卫星接收,用网络来做备份,不同的信源下面接的是不同的编码器组,通过组播的方式把信源编码以后传递给下面的分发源站,分发源站用组播的方式有一个好处,就是可以平滑地、无缝地去扩容分发源站,但是这个好处也带来一个问题,分发源站有很多的服务器,这些服务器如何同步地执行切换流的指令是目前需要面对的问题。针对这个问题引入了Redis元数据的概念,通过控制所有源站的控制指令,通过后台对Redis元数据控制,实现所有源站在发现信源或者是编码器组故障,或者有业务需求要切流的时候,一致性地推动所有的分发源站做切换动作。
接下来是无缝切流,做过CDN的人都有所了解,如果源站出了问题可能会导致全网故障,所以保障源站的可用性是比较大的问题。源站从信源到编码器,一直到分发源站都是多备份的,在多备份的情况下如何平滑地在多备份之间进行切换,这就带来了一个技术挑战。一个是用户的体验(流畅性),一个是竞品网站的清晰度,产品和运营PK最后的结论就是让技术解决。
编码器1、编码器2是相互备份的关系,提供同样的清晰度,编码器1提供三档清晰度,编码器2也提供同样三档清晰度,源站集群向一级、二级边缘下发,如果产品要求拼播,会把第二档的清晰度作为默认清晰度下发,当发现用户卡顿比较高、流畅性比较差的情况下,把默认清晰度动态切换到码流比较低的状态,用户体验可以比较高,编码器第一组挂了,可以快速地切换到编码器第二组,用了清晰度3,如果流畅性比较好,尝试让用户切换到更清晰的程度,在同平台的竞争中我们也有一定的优势。
这是技术细节,视频编码分三类帧,一类是I帧、关键帧,还有就是B帧,是通过I帧的相对运算集散出来的,压缩比可以达到50%左右,压缩效率更高。还有B帧,B帧要通过P帧或者I帧做演算,压缩率会更高,因为极度压缩,里面产生了很多片断的状态,有些B帧需要前后帧结算,所以在切流的时候,从第一路流切到第二路流,第一路流没有到关键帧就切的话,前面的帧是解析不了的,所以必须在第一路流的I帧播放完以后马上切到第二路流,第一套方案上线后出现一些问题,切到第二路流的时候,只追求了一个时效性,非常快速地切过去,但是因为编码器之间时效性、准确性对得不是很齐,会产生不能解析的问题,因为它是P帧,缺少前面的关键帧,所以导致P帧不能解析,甚至B帧也不能解析,所以这块会产生一个花屏,时间非常短,用户会发现突然花一下,后面等I帧到了以后会继续流畅地往下播。目前芒果TV的改进方案就是解决这个问题。
最后是全网边缘的同步切片,芒果TV目前封装方式很多,编码器到分发源之间是用RTMT组播,组播之后进行封装,因为需要HLS格式,如果同时把这些路往下传,以后可能还有更多路,刚才说264、265、AAC等等这么多路同时往下传的话,会员带宽和成本是扛不住的。因此采用一路流直接传到边缘,在边缘做转封装,这样的好处是成本可以大幅下降,而且压力比较轻。
但是碰到边缘A站看直播流的时候,突然边缘A站宕掉或者有什么意外的情况需要重试,通过调度到边缘B站,到边缘B站再获取同样时间点片的时候,由于每个边缘到源站的时延是不一样的,包括跳过几级路由也不一样,可能经过其他中间层的传输,所以它到边缘的时候时延是不一样的,虽然系统时间一样,但是流的时间是不一样的,中间就产生了差,因为播放器都是有缓存的,播放器缓存如果网突然有问题了,拿不到缓存,去后台做重试,去边缘B站,去继续拿流,但是因为两边产生的内容差,就发现拿流的时候,会出现重复情况,有的时候时延情况更严重,给用户带来的体验比较差,要解决这个问题必须在内容上去做标记,来实现切片的时候是内容对齐的,所以就考虑了在刚才说的I帧、P帧、B帧中间插一些注示帧、SEI帧,自定义一些信息,把拿到FLV流做封装的时候,读到这些信息的时候就知道在什么位置做切片,这样全网所有的切片都是一致的,从A边缘跳到B边缘、C边缘中间都是非常流畅的。