阿里云CDN高级技术专家阙寒:Tengine直播最佳实践,


在上周刚落幕的开源人盛会IT人也迎来了开源盛会LinuxCon + ContainerCon + CloudOpen中国(简称LC3)大会上,和通数据库CDN团队的高级技术专家阙寒(花名),为大家分享CDN在使用Tengine构建直播系统的一些实践。

Tengine是由淘宝网发起的Web服务器项目。它在Nginx的基础上,针对大访问量网站的需求,提供更强大的流量负载均衡能力、全站HTTPS服务、安全防攻击、链路追踪等众多高级特性。团队的核心成员来自于淘宝、搜狗等互联网企业,从2011年12月开始,Tengine成为一个开源项目,团队在积极地开发和维护着它,最终目标是打造一个高效、稳定、安全、易用的Web平台。

阙寒分享的题目为Tengine直播最佳实践,整个分享分为三个部分,第一部分是对直播整体介绍和音视频知识普及,第二部分是系统软件的架构,第三部分是和服务质量相关的内容。以下为分享内容全文。

在分享的最初,阙寒简单介绍了和通数据库直播的整体解决方案,覆盖了推流端、直播中心、CDN分发网络和播放端。推流端一般是通过DNS调度后访问就近的CDN节点,将直播流推到边缘节点,经过边缘节点加速后经过直播中心,在直播中心进行转码、截图、录制、水印、切片等直播处理,播放的时候也是先经过DNS调度,访问就近的边缘节点,当节点MISS的情况下,会访问直播中心将这路流拉到边缘。

image

对于推流来讲,一般都是RTMP协议,播放包括RTMP、FLV、HLS三种协议,前两种协议都是流式的播放,一般延时在3秒左右。HLS是文件的分发,延时在10秒左右。对于音视频格式,音频主要支持ACC,视频支持H264和H265。

流式直播

RTMP和FLV这两种协议是流式直播,它的特点就是长连接,一个推流或者一个播放连接可能会持续几十分钟、甚至几个小时,在长连接上传输的数据就是一帧一帧的帧数据,每一帧数据都是FLV tag形式封装的。

image

发布与订阅

对于直播来讲,推流和播放是一种非常典型的发布和订阅的关系。两台Tengine服务器,有两路流,第一路流是主播推流发布,两个播放端形成订阅关系。第二路流发布并不是主播推流,而是从另一台Tengine服务器拉流形成发布,三个播放端形成订阅。正是这种机器与机器,节点与节点之间的级联关系,就构成了CDN的分发网络。

image

音视频帧

对于音频来讲,音频帧一般是可以独立编解码的,播放端在得到任何一帧音频帧都可以直接渲染出声音来。但是视频就不太一样,视频帧分为关键帧和非关键帧,关键帧具备独立编解码的能力,而非关键帧就依赖于关键帧才可以进行渲染。关键帧携带的信息量比较多,几K甚至10几K大小,非关键帧只有几K,甚至1K以内。两个关键帧之间的间隔称之为1个GOP。对于视频播放来讲,一定先从视频关键帧开始发送,不然播放端就花屏,要么就需要等到下一个关键帧出现为止。

其实对于静态文件加速来讲,服务器上存储的都是静态文件的内容,内容的访问是不会变更的。但是对于直播来讲,服务器上缓存的数据会随着时间的推移而变化,永远缓存最近出现的视频关键帧序列。下图第一排描述了前一时刻,服务器缓存了这一部分视频关键帧,第二排就是当新的关键帧出现了,缓存的数据也向后移动,前面的数据会被删除掉。

image

比如一场直播有两个小时,从头到尾7200秒,假设这个视频流10秒一个关键帧,就意味着会出现720个关键帧,也就是服务器存储的数据会更换720次。

时间戳

对音视频来讲,另一个比较重要的属性就是时间戳。正常来讲,视频流的音频和视频的时间戳都是单调递增的。而且任意时刻,两者之间的时间戳不会相差太大。

image

线上比较多出现的异常情况有三种:第一是主播端推流,时间戳回退,直接跌零,第二是时间戳随时时间增长,四个字节表现不下,会出现回滚溢出,从零开始;第三是音频和视频的时间戳本身是单调递增,当把两者叠合在一个世界轴上的时候,就不是单调递增了,可能会出现各种回退的情况。

这三种情况都是对服务器对计算缓存大小的时候,出来一些异常,非常影响观看体验。所以建议在推流的时候,推流端时间戳尽量保持单调递增,尽量避免如上三种情况的发生。

音视频头

一般来讲,音视频头要先于其他音视频帧发送的,因为播放端会依赖它来进一步解析。服务器本身也支持推流端不断开重推的时候,切换音频头和视频头。
image

系统软件架构

这幅图大概列了一下和通数据库CDN的网络架构,推流端会经过边缘节点、二级节点的加速,推到直播中心。对于播放来讲,也是就近访问边缘节点,MISS的话会访问二级节点,还是MISS会访问直播中心。
image

直播中心

直播中心有两个组件,一个是Tengine流媒体直播服务器,另一个是调度组件。因为直播中心可能会承载成千上万甚至十几万的路流,这里引入调度组件是为了做负载均衡,确保如此多路流能够平均负载在每台机器上,同时也能够进行流的查找。这样的话,在推流的时候,根据负载均衡去分配一台负载相对比较低的机器,播放的时候,也比较明确的知道这路流在哪台机器上,然后进行返回。

image

单机推流和播放

对于流媒体服务器来讲,一个核心要解决的问题就是单机的推流和播放的问题。在和通数据库这边,Tengine主要使用多进程的工作模式,首先要解决的问题是:如果推流请求和播放请求不是一个进程处理的情况下,如何能让播放看到画面?

早期的架构比较简单,第一个进程接受到进程后,它会同时把这路流推给其他所有worker,这样保证其他worker都有这路流,播放到任何worker都无所谓。这个架构撑了一段时间,我们就发现缺点很明显,当这台机器出现两三百路流的时候,负载就会非常高,而且这个架构没办法通过增加CPU的个数来解决负载高的问题。所以我们进行了一段改进,把主动的push改成被动的pull。第一个worker接收到推流后,不主动推给其他任何worker,如果播放被其他worker捕获的话,处理播放请求的worker会从接受推流的worker处发起一次拉流,这里面worker之间通信使用Unix套接字,并使用共享内存记录每路流和每路worker之间的对应关系,当然也包括一些异常处理。

在这个模式下,我们进行常规压测,大约一台机器可以到两三千路流。

image

其次,每台机器也会提供和流操作的相关接口。包括单路流的查询,这台机器一共有哪些推流,和断开推流、断开播放等操作。

image

边缘节点

对于边缘节点或二层节点来讲,大概是下图的架构。右边是接受推流,Tengine接受到推流后,直接转给直播中心,对于播放来讲,需要先经过一致性hash,减少回源流量,再进行回源拉流。一致性hash,确保一个节点上对于一路流来讲,只有一台机器回源,节省了从L1节点到二层节点的流量。

image

拉流合并

在Tengine的多进程模式下,虽然有了一致性hash,但是这台机器可能有多个worker,早期模式是每个worker有多个播放的时候,各自回源。Worker数越多,回源数越多。所以我们做了一次拉流合并的操作,一个worker在回源的时候,会先进行共享内存的查找,如果没有的话会自己发起回源,如果有的话它会向已经回源的worker进行一次拉流,这样来确保最终回源机器只有一个进程在回源。这里也包括异常处理,和回源连接断开、重试等逻辑操作。经过一致性hash和拉流合并的处理,基本能确保一个节点上,对于一路流来讲只有一个回源连接。

image

另外,很多直播平台,都会要求各家CDN在自己分发的同时,也转推给其他家。和通数据库主要在边缘节点完成这些动作,在回转推中心的同时,也会转推给友商或客户源站。这里使用了动态配置来支持功能,并且转推机制也支持重试和地址重新获取。

服务质量——首屏

第一个比较重要的就是首屏,播放端从点击播放到能看到画面的时间差。和通数据库对于首屏做了这么几点优化,一个是各级的Tengine服务器保留这路流的gop cache,确保每一个播放都从关键帧立刻开始发送,同时这里还要减少各级之间无效数据的传输,如果节点之间传输了5M数据,推给客户端4M数据,1M数据对于客户播放是无效的,这块其实对首屏也有影响。其次,还要减少服务器以之间及节点之间的RTT交互。

image

其实对于首屏来讲,除了软件上要做性能调整外,更重要的一点还是服务器自身的数据收集。这里大概列了一下,服务器端针对一次播放,采集的一些数据,第一列是时间点,第二列是每秒发了多少视频帧,第三列从服务器角度来看,发送一定数量的视频帧大概花了多少时间。

image

这里面我们记录到这次播放是5毫秒,边缘命中了,在5毫秒内立刻发送200毫秒的时间戳,或者统计80帧的时间消耗。做这个采集是为了和客户端的打点日志进行匹配,有可能服务端记录的数据好得不得了,但是客户端打点日志首屏很差,所以可以进行匹配。这里面可以涉及其他问题,比如DNS解析时间,服务端统计不到,播放端和服务器行为不匹配,造成首屏渲染很差。

服务质量——卡顿

关于卡顿,从网络链路上来讲,有以下几个方面优化。

第一可以针对上行链路进行优化。主播一般会通过LOCAL DNS进行解析,获取就近边缘节点,其实我们更推荐用HTTPDNS,这样调度会更准确。第二针对下行覆盖,优先使用本地覆盖,在水位不够等情况下,退而求其次使用大区覆盖。对于内部传输可能出现的抖动,我们引入了各种切换和传输优化机制。

另外,对于音视频帧来讲,推流的码率可能也会造成卡顿,码率越高卡顿更严重,尤其是弱网客户对于高码率会有更高的卡顿。

在服务器端,会做链路监控和采集,来判断卡顿的原因,正常来讲音视频帧的每秒帧数是固定的。应该是一条平滑的直线,如果出现下图的突刺,一定是链路出现了抖动,播放的直观感受就是卡了一次。

image

我们也会采用全链路监控,来记录每一个链路服务质量,使用不同颜色标注出链路的好坏。红色那条一定是出现过严重抖动。同时我们也会在每条链路上收集比较详细的数据。媒体层会记录音频帧率、视频帧率,码率、时间戳等数据,从业务层,会记录首屏、卡顿、错误码等数据,传输层会记录RTT、重传、拥塞窗口等等。记录的信息越详细,问题越容易发现。

image

我们也会记录一些比较详细的访问日志,分析卡顿的原因。从服务器端角度来看,如果出现下行堆积,丢帧等等情况,可能是网络覆盖的问题。如果与客户的打点日志去匹配的时候,发现播放一切正常,还是报卡,那就需要对齐数据。

image

Tengine官网:http://tengine.taobao.org

Tengine Github:https://github.com/alibaba/tengine

和通数据库CDN:https://www.aliyun.com/product/cdn

相关内容