BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

徐立:视频直播的三个技术难题
录制于:

| 受访者 徐立 关注 0 他的粉丝 作者 InfoQ 关注 9 他的粉丝 发布于 2016年11月14日 | Google、Facebook、Pinterest、阿里、腾讯 等顶尖技术团队的上百个可供参考的架构实例!
30:55

个人简介 徐立,前盛大创新院云计算研究员,七牛创始合伙人,现担任七牛产品副总裁。从无到有开创了七牛直播云产品线和完成其商业模式验证,负责七牛直播云的整体研发和管理,其带领的研发团队开发的直播云服务覆盖数以亿计的终端用户,服务于数百家企业。作为Go语言的早期实践和布道者,曾参与撰写国内第一本Go语言图书《Go语言编程》,和翻译《Go语言程序设计》,参与Docker/Container技术的早期布道,是 Golang/Containers/Distributed Systems 技术领域的忠实爱好者 。

全球架构师峰会(International Architect Summit,下简称ArchSummit)是由InfoQ中文站主办的一次全球性架构师峰会。ArchSummit专门针对架构师人群,讲述与架构和架构师相关的各方面趋势、技术和案例。这也是继QCon之后,InfoQ中文站主办的又一次高端技术盛会。

   

2. 您能介绍一下为什么选用Go语言以及它在做直播服务的时候的优势以及不足吗?

徐立:这和我们当时起步做这件事情有关系,原本我们需要一个直播的服务器,相当于流媒体的服务器,当时看了一下开源的,除了nginx rtmp module,没有特别好的选择,市面上还有另外一家,这两种都是C/C++的,但并不是由于语言的差异我们没有选择开源的,而是根据在一些指标上的要求没有选择第三方开源的,比如像nginx那种使用方式,它贴合我们的业务系统去架构一套视频分发网络,我们判断下来是有差异的,所以没有去用。当时有个选择,是把开源的拿过来改还是自己写一遍,我们看开源的时候发现如果改开源的,比如nginx的rtmp module,很多思路需要沿用他原来的写法,十几万行代码里大部分都是nginx的,rtmp这一部分相当于是它的插件,做直播不只是用rtmp插件就结束了,有很多工作要做,有一些跟视频的封装等底层的细节有关系,再做一些其它的逻辑处理,比如服务端的一致性缓存和丢帧等,这些都不是开源软件具备的,改的话跟重写并没有太大的区别,并且成本可能会更高。它需要按照类似nginx那种配置式的方式去部署,大规模直播的云服务系统不是静态配置式的,我们更希望做到动态智能调度方式的。这需要我们在底层的技术是完全可以自己掌握的。基于这个原因我们也需要从底层开始实现,用go还是c++,这是到工具层面了,擅长用哪个就用哪一个,用go写没什么问题,而且go在处理大规模并发的情况下确实有充分发挥硬件的优势。所以就用它写了一些基础的组件,比如rtmp的协议封装, rtmp的server,还有流媒体这块,比如TS的封装和切割,服务器,还有整个业务的逻辑后端、调度系统,这些都是用go来写。

   

3. 您这样一说,我感觉一些云通讯厂商还有视频网站这种解决方案,他们用c的话,其实工作量也不小,对吧?

徐立:把业务理解消化透了之后,你会发现很多事变得越模块化会更好,再完成组件间的组合关系,开源能解决局部的问题,但不能很好的解决全局的、系统架构层面的问题,开源在软件工程架构方面做得还是不错的,但要贴近业务的时候,从业务需求的角度思考的话,其实它是一个系统架构,不完全是软件层面的架构。

   

4. 在视频直播技术方面有没有像Nginx与Lua(春哥的OpenResty)一样高效的组合?

徐立:其它的目前还没有发现。以前有,后来没有开源。Github上能够找到的是nginx rtmp module,但是看commit的历史记录你会发现大概有好几年它主要的代码都没有更新,跟现在市场脱节还是比较严重的,作者没有执行后续的维护,停留在能把功能跑起来,这和做一个大规模稳定的高可用服务是两码事。

   

5. 这半年来,很多云厂商、CDN厂商纷纷推出了自己的直播解决方案并宣称解决了一些直播服务的技术难题,在您看来直播的技术难点有哪些?

徐立:从最终的用户体验角度来讲,就是三个:一个是打开的速度够不够快,也就是首屏加载时间,大家现在都在说能不能秒开,这是第一个点。第二个点,直播的过程中卡不卡顿,最好是不卡顿,这是比较好的体验,因为卡顿比较影响用户直观的感受。第三个,是延时,延时是不是足够低,达到互动的诉求。就这三点。

   

6. 我在GitHub上看到七牛有个HappyDNS项目,您能简单介绍下这个项目以及它的应用情况?

徐立:它主要解决的是国内比较复杂的DNS污染和劫持的问题,DNS是一套很好的架构,但是在网络比较复杂的情况下用的不是特别好,会看到很多地方存在本地运营商劫持dns放广告这种问题,尤其像直播,如果是走rtmp协议,它的端口默认都不是80的,网络传输时,中间代理商有可能是不通的,一旦运营商做了dns的劫持,可能就直接block了。有一个解决方案是把dns解析这个逻辑换掉,默认走localdns,先去请求http server,由http server告诉我应该正确的解析到哪个ip,再通过IP和端口的方式直接去访问目标主机,避免local DNS解析出现污染或者劫持的问题。

   

7. 也就是绕过递归查询的时间?

徐立:绕过递归查询时间是一方面,更主要的是解决被运营商劫持的问题。

   

8. 接下来我想问两个LiveNet的问题。首先LiveNet的SDN技术采用的是什么?DPDK还是?

徐立:它是打引号的软件定义网络,我们没有把像交换机层面的软件定义网络技术用在上面,它的实时流网络有几个特性是不一样的,在网络结构上会跟之前的多中心树状网络不一样,多中心的树状网络拓扑方式是按照区域来的,分几大区,每个区有核心的大的节点,围绕大节点会有边缘的小的节点,这种方式有几个问题,多中心会带来一致性维护的问题,这是很自然的现象;第二个是,它拿来做分发的时候线路是比较有限的,比如从华南到华北是跨了两大区,如果中间穿过华中或华东的话就有可能跨好几个区,如果大区之间的省间网络交换出现拥堵,另外一个片区就可能被Block,整个片区的体验受到影响,但是它这个时候又没有太好的选择,在链路上是不够灵活的,不能动态组合。有另外一个方式可以规避这个问题,我可以做两个平面,第一个平面还是大区划分,是静态路由,平行的做另外一个平面,也是按大区划分,但是走另外一个路由,当第一个平面不可用的时候切到另外一个平面,但这种方式成本很高昂,建设和带宽的成本都会比较高。我们定义一种方式,用程序这种动态的方式去定义路由怎么走,在节点上去中心化,区分两种角色,有状态维持的和无状态维持的,有状态维持的角色是调度器节点,调度器是一组多活,另外一种是无状态的流服务器的节点,跑流量型的,这种没有状态维持,可以任意的宕机,宕机之后它的状态可以被平滑转移到其它的流媒体服务器上面。在整个网络层面上有点类似像去中心化,没有多个中心了。它的路由完全是由调度器做决策,怎么做决策呢?所有这些流服务器节点都需要把自己的健康信息,比如当前的I/O负载、计算量和其它节点之间连接的丢包、延时等等这些信息上报给调度服务器,调度服务器根据这些信息动态的组合一个线路。一个直播在被推送到边缘节点时可以有n条线路选择,如果中间一条线路block了,它可以再选择另外一条,调度器做动态的实时决策再返回给它应该走哪一条。这种方式是用程序智能的方式去定义路由,是打引号的软件定义网络,它和专业的software defined network定义是有本质差异的,专业的SDN是在协议层面,在四层模拟二层,做包的解包和封装,相当于把物理网卡做的事情搬到cpu去做,做到灵活的控制,但是性能是比较堪忧的。我们的软件定义网络更多的是说线路的动态调节,基于大量侦测数据的实时反馈做线路的选择,保证线路不会因为运营商的网络交换或者省间网络流量交换拥堵之后形成block,它可以灵活的切线路;第二点是它的节点是可以做到多活的,无状态的节点宕掉的话可以平滑到转移到其它节点,状态不丢失。

   

10. 能介绍一下LiveNet在传输层协议上的创新主要是哪些内容吗?您提到协议层上是有些创新的,但是我看七牛直播采用的传输协议还是RTMP的

徐立:RTMP已经是应用层的协议了,它在传输层以上做了一些网络抖动、网络丢包等相关的算法优化,但它本身是不关心内容的,比如我们说的http协议是关心内容的,RTMP协议也是关心内容的,它的内容格式比如flv的 tag,http协议里分headers和body,内容的形态都是需要考虑的,协议这层我们会更贴近往下一层,在传输层以上做一些逻辑,做到我传flv tag rtmp的数据可以,传ts的封装也可以做直播,传其他格式做到流式的上传和下载也可以,内容不关心,只关心传输层面上的一些事情。

   

11. 接下来想问一下CDN的部分。我们知道直播服务离不开CDN,您在别的分享中也提到和第三方 CDN 合作的过程中会遇到一些问题,能不能分享下具体遇到哪些问题,怎么克服的?

徐立:这些问题比较偏向网络层面,CDN本身技术实现的方式还是比较偏向多中心,多中心的带来问题也比较明显,线路比较有限,这是第一个。第二个是出问题的时候没有特别好的感知方式,比如说报卡,或者看不了,需要人工的去看节点的状态。我们现在做的方式是把网络结构变了,带来几个优势,第一个是节点之间可以任意组合,意味着容错性更好,线路可以更丰富,不局限于有限的那几条线路,在网络拥塞的时候可以比较智能的切出去;第二点它在程序上做到了用质量数据的方式做调整,比如省间网络会堵,运营商之间的流量会堵,之前CDN的做法是需要人工去看告警,再人工介入处理,但是我们能够做到数据如果快速及时反馈,这套系统自己本身可以灵活的进行一些线路的调优。另外一点,在节点的故障容错上,这跟整个的感知逻辑有关系,比如CDN如果没有终端的SDK的话,节点出现问题的时候它只能被动的以心跳的方式去做感知。有终端SDK的话,它感知的方式会更及时。一旦有故障,有这个终端的好处是可以平滑的把连接切到另外的节点上,容错性更好。

   

12. 七牛直播除了硬解码这部分是MediaCodec之外,软解码选择的是H.264,为什么没有采用H.265或者其他开源的,比如google的vp8、vp9这种压缩比更高的编解码方式?

徐立:我们做SDK软件架构的时候做了分层模块设计,分为采集层,处理层,编码层,封包层和推流层,每一层都是模块化并且是开放式的,像采集这一块除了支持摄像头采集屏幕录制,音频的采集之外,还支持自定义采集,比如说把无人机拍的影像传到SDK里,也可以编码之后再推出去。在处理层也是开放的,SDK除了自带美颜,水印这些通用的刚需的处理之外,在做特效滤镜的时候也可以支持自定义的滤镜处理,这都是开放的。编码层也是开放的,可以用H264,也可以用H265,也可以用VP8、VP9,这些都是支持的,只是需要使用方自己去权衡,权衡的因素会有很多,比如在移动端做H265的编码,运算量会比较大,一般做app的工程师不会倾向去考虑,因为手机发热量会很高,耗电很快会影响用户体验。其他的协议格式,比如VP8,VP9,在chrome的webkit里支持的挺好,但是在其他的终端上就不一定能够覆盖。需要跨平台的把编码器、解码器都移植掉。用H264不是我们决定的,是市场决定的,这个太普及了,所有的电子设备、终端都支持H264,它现在是最普遍的一个编码协议。

   

13. 您刚才也提到,比如直播中的弹幕、美颜、滤镜等等,我把它们理解为一些插件化的特性,这些计算一般是在编码部分而不在传输层或用户端解码部分(当然弹幕不是的),他们对直播中延时的影响是怎样的?七牛的优化策略是什么?

徐立:它属于功能的增值部分,我们设计SDK的时候考虑的是开放式架构,所以跟功能相关的部分都设计成开放式,尽可能用组合的方式把另外一个新的功能纳入进来,而不是自己再做一遍,我们的SDK更专注于传输及传输控制这一层,跟功能相关的这一层是开放式的,可以任意组合市面上已有的功能单元。它对延时没有影响,比如弹幕,弹幕跟直播是两回事,弹幕走的是websocket文本的传输,在协议层面跟视频直播是隔离开的,它也不占延时,因为它不消耗图像处理。只有一些特效,比如美颜或滤镜会消耗计算资源,可能会造成处理上的延时,这取决于机型的配置,建议的优化策略是跟图像处理相关的使用GPU来做,视频编码也可以用GPU来做,考虑到画质和兼容性可能有一部分需要用软编的方式做。也就是说有可能视频有一部分是用软编的方式做,图形、美颜、图像处理、水印、滤镜这些用GPU做,同时双工进行。

   

14. 我之前也做过一些视频方面的工作,像这种实时直播的东西如果用GPU的话,直播视频流时间可能不会很好,像您提到的这种方法感觉还是比较好的

徐立:还有一个需要考虑的是,如果运算量计算不过来的时候应该减少输入,比如编码计算不过来了,或者图像处理单元算不过来了,这时候应该在采集这一层可以做到一些控制,比如你可以不用采集那么大的分辨率,比如在移动端采集1080p的,再去做编码的话,手机要算死了,采集这么大的一张视图,它的体积本身就好几M,编码器就挺吃力的,你可以把采集的大小放小一点,这其实不影响画质的清晰度,这是一方面。另外如果你采集30帧,也可能编码器还是算不过来,那你可以选择一些丢帧的处理,丢掉之后运算量小了,而且传输体积小了,这样可以保证低延时、更流畅。

   

15. 在解决直播过程中的卡顿现象时,大家都采用选择性丢帧策略,您能详细介绍一下对关键帧粒度处理的细节吗?

徐立:丢帧只是其中的一环,要解决卡顿的问题,要从推流端进行考虑,从网络这一层进行考虑、还要从播放这一端进行考虑,共三个环节。在推流端这个环节,它分为采集、处理、封包、推流,造成卡顿可能是因为计算单元跟不上,比如编码延时,或者画面出现一帧一帧的编不过来了,这都会导致卡顿,这时候你可以在编码之前就有选择性的丢掉一部分数据,减少编码的运算量,达到设备的性能、配置跟和当前要处理的运算量是ok的,这是第一步。第二步是你得观察推流端的网络是不是OK的,如果带宽不够怎么办。那就要动态的调码率了,比如原本你推1.5M的高清流,发现主播网络带宽不够,可能只有1M,那你只能推800K的或者500K的,这时候需要动态的调节码率,但是要保证连接不中断,这是一个优化的技巧。有时候不是主播带宽的问题,他的带宽容量是够的,但是网络链路质量不太好,可能会丢包,延时非常高,这个时候可以进行丢帧,减少传输的量。但是丢帧的话需要注意一些技巧,不能乱丢,乱丢可能造成花屏,需要注意一些细节,你可以把整段GOP内的内容丢掉,保证关键帧是连续的,画面是连续的,图像信息是完整的,不会花屏,还会高清,减少传输的体积,这是在推流端这一层做的一些优化措施。在网络这一层,这一层是动态调度,连接已经建立了,但是节点的负载可能会高,可能会有丢包或者延时这种不稳定的情况,这时候需要推流端去感知,感知之后去请求调度服务器,调度服务器告诉它你应该切换到更好的节点,它再返回给app的业务层告诉它应该重新去建一个连接,无缝的完成切换,这是属于网络层面的。网络层面还有可能出现节点沦陷,转发的节点宕掉了,不是推流端的问题也不是播放端的问题,这时候还是需要调度器来解救,基于节点的健康状态和链路数据帮他决策另外一条线路,分发到最终播放端的节点,播放端节点再跟播放器建立连接,这种影响就会很小,直播端不出问题,分发端不出问题就没有全局性的问题,播放端个体网络的问题影响的是个体,不影响全局。更重要的是我们要解决推流端和网络分发层的各种网络不可靠、机器性能不可靠的因素,软件层面的也要,网络层面的也有。还有一些可能是跟运营商DNS劫持有关的,局部地区可能会出现这种情况,那就要用到我们刚才说的httpdns这种技术。

InfoQ:好的,谢谢,我的采访就是这些。

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT