来自Revvel的团队的Greg Femec在re:Invent 2017大会上分享了他在构建视频转码服务中遇到的挑战,以及构建基于Serverless架构的视频转码平台的经验。Revvel团队将视频转码服务从AWS EC2迁移到AWS Lambda和S3上,实现了整个转码的Serverless化,节省了大量费用和运维成本,并且将时长2小时的视频转码从4-6小时缩短到不到10分钟,从而将更多的时间投入到核心服务的开发和优化当中。LiveVideoStack对其进行了摘译整理,点击『阅读原文』观看Greg的分享视频。
作者:Greg Femec,Revvel资深软件开发主管(Principle Development Lead)
听译:王鸿蒙
责编:Ant
Serverless系统架构具有自动扩容、按需付费、无需服务器部署和运维以及高可用性和容错性的特点。AWS Lambda是著名的Serverless云服务提供商,在AWS Lambda上的一个典型Serverless应用往往通过事件驱动的方式去触发对预定义函数的调用。事件源可以有很多种,主要分为3类:
AWS Lambda典型的应用包括:
在视频编码处理中,并行编码算法有多种,根据并行级别可以分为GoP 级、帧级、Slice 级和宏块行级。视频编码的这种特点使得它可以很好的利用AWS Lamda的并行处理的特性。Revvel团队在之前构建视频转码服务平台过程中遇到过许多挑战,主要体现在以下几个方面:
在早期Revvel团队使用了SaaS方案。但是由于视频的来源不同,我们很难在这个方案中获得对于视频转码更高的控制权。同时成本效益并不高,尤其是新增转码格式的边际成本并未随着用量增大而显著降低。
我们也在AWS EC2上尝试建立自己的视频转码服务,成本得到了一定的控制,视频的控制权也增大,但随之而来的是运维方面的挑战。这些挑战表现在:
我们为什么使用Serverless?
Serverless的好处明显:没有冷启动问题,可以快速扩容缩容,没有资源浪费,运维问题更少,并发量更大(AWS Lambda默认并发执行上限为1000,我们调整为2000,但这并不是硬性限制),以及灵活的资源配置(可以快速重新对资源进行分配)。
Serverless下转码的挑战
输入的视频文件往往较大(有些有数百GB),我们不希望等文件下载完成才开始处理,并且我们在Lambda中的容器也没有这么大的存储空间。另外,视频转码工具一般假定输入输出为完整的视频文件,无法进行块级的处理。同时,如我们之前提到的,HD视频转码往往耗时好几个小时,而且转码一旦开始,很难暂停和重启。
我们的解决方案
我们的高效视频转码解决方案使用类似于MapReduce的分治法,把视频切成5秒(时间可以调整)的小块,在map中进行转码,在reduce中进行合并,输出我们需要的格式, 比如无交错视频(Progressive MP4)和MPEG-DASH。对于HLS,某些情况下我们可以直接使用map的结果作为TS块,有时也做一些后期处理,尤其是需要加入DRM时。同时需要避免在本地磁盘上缓存完整的视频大文件。
我们使用的工具包括AWS Lambda(实时缩放、并行处理的能力)、S3(支持分段上传,按范围请求数据)、FFmpeg(转码领域的瑞士军刀)以及Python(AWS Lambda对Python有很好的支持,Revvel团队熟悉并大量使用该语言,并可以对C代码进行很好的整合)。下面对Serverless转码的架构图进行简要说明:
图:转码架构图
我们的输入和输出处理基于S3存储。首先,我们从不同的存储位置获取视频源文件,统一存储在S3上,执行map(图中所示Chunk Lambda Function)开始进行处理。严格来讲,在这里我们可以并行运行任意数量的map,视频文件中的每组5秒数据块可以被分别获取,这些5秒数据块的计算相互独立,每一个的处理都不依赖于其他的5秒数据块,数据块的分发和执行只取决于我们现有的CPU总核数,以及并发的Lambda function执行数量。所以,这就允许我们一次运行多组程序来处理ts块,而这步处理的结果将被存储于另外的S3存储桶中。下一步,我们继续在这些文件块上进行reduce。通过对文件块进行相对简单的reduce操作,并将他们合并,可以生成MP4文件;如果要生成DRM文件则要更加复杂的过程,图中所示即是生成DRM后的HLS文件的例子,而DASH文件的生成过程与之类似。
下面我们讲解块函数(Chunk Function)操作中的细节。
块函数(Chunk Function)工作说明
之所以叫块函数,是因为我们要通过这个函数生成ts文件块。如果我们想生成一个文件块,首先就需要解码输入视频中的一小部分,然后将其转码到想要得到的分辨率/码率,最后,将生成的TS文件块上传到S3中。这里面临如下两个主要的挑战。
图:块函数(Chunk Funtion)工作流程图
从上面可以看到,我们不再需要下载整个文件,而只是对其中一小部分进行操作即可。因此,我们的挑战主要来自于如何在这种情况下实现解码。通常,我们使用FFmpeg帮助我们完成大部分解码操作。FFmpeg支持有大小范围请求的HTTP请求,FFmpeg常常读若干字节后前后跳转,产生大量的HTTP请求来对相同文件块反复读取,造成巨大的性能消耗。为此,我们在Lambda function中对S3进行了缓存,做法是在Lambda里启动一个HTTP服务,代理所有FFmpeg对S3的读取请求。我们要做的是从S3中得到比FFmpeg请求更大的文件块,并将其缓存到内存中,避免反复对相同文件块的反复造成的开销。另外,由于视频处理整体是从前往后的,所以在FFmpeg处理一个块时,我们也会主动预取下一个数据块,以免出现CPU等待IO造成的性能损失。
首先, 动态链接的FFmepg在lambda中运行不是很稳定,所以我们目前基本都是使用的静态链接。虽然文件尺寸更大,但仍在Lambda的限制之内。
另外,创建进程也可能出现问题。在Lambda里使用fork创建进程时,子进程会继承父进程的所有属性,这里面也包括了运行着我们代码的lambda沙箱,因此在子进程里常常会意外发现一些自己并未创建过的东西。在我们的实践中,在Python代码里fork的FFmpeg进程继承了沙箱中的某些文件描述符,特别是标准输入,这偶尔会造成一些bug,我们可以将文件描述符关闭来解决这些问题。另外,如果前后执行多个Lambda function,容器可能会被重用,这意味着之前创建的进程会一直保持到后续的执行过程。因此,lambda function即使在执行错误的情况下也要正确清理现场。
合并函数(Merge Function)
图:精简合并函数(Merge Function)工作流程图
当我们的文件经过map步骤处理后,形成小的ts文件块进入到精简合并操作步骤。其中,比较常用的就是生成MP4文件。在这个过程中,合并函数读入.ts的文件块,合并为MP4文件,然后上传到S3中。这里遇到的问题主要集中在文件输出上。
输出文件的挑战
相对于输入文件,输出的视频文件往往很大,lambda没有足够的临时空间存储。FFmpeg虽然支持FTP输出,但在输出MP4时,它输出大部分数据之后,还会跳转到文件头插入一些信息。这个时候我们就要引入S3的文件分段上传功能。我们在Lambda function中启动一个定制的FTP服务,类似适配器,将FTP输入适配到S3的文件分段上传功能中。由于S3不需要按顺序上传,每段大小也不需要相同,因此我们可以从第二段开始上传,最后再上传包含文件头的第一段。
连接函数(Concat Function)
图:连接函数(Concat Function)工作流程图
如上图所示,我们看一个输出DRM后的HLS格式文件的例子。图中,我们读入.ts的文件块,在reduce过程中进行加密,并将加密文件上传到S3中。我们将其合并以提高缓存效率,因为CDN中为列表中每个HLS只创建1个对象。这里的问题主要集中在执行方面。
执行的挑战
我们面临处理时间方面的挑战。举例说明,当我们的AES加密样本需要重新打包ts流,由于视频较长,无法在lambda限制的5分钟内完成。我们的解决方案是将lambda function进行菊链连接,这样如果前一个lambda function没有处理完,就把当前上传状态序列化给下一个lambda function继续处理。这里要注意的是,上传和下载速度不一定是对称的,当上传速度成为瓶颈时,需要限制下载速度。我们曾经遇到过下载数据过多而来不及上传导致的内存不足,所以当你进行类似的流式数据处理时,要加上一些背压(backpressure)。
下面我们讲一下部署的问题。
部署和CI/CD流水线
图:部署和CI/CD流水线
考虑到可重现性,我们通常选择在Docker容器中创建我们的lambda function。创建lambda function所用的git sha和脚本哈希值会成为zip文件名的一部分,这是我们对于不可变基础架构理念的一种探索。但我们生成的新zip文件实际上不会立即替代现有的lambda function,而会生成一个新版本。我们可以对新版本进行测试,确保它可正常工作。当我们足够自信代码没有问题的时候,我们会更新产品环境中的lambda function的别名,使它指向新版本,这是新代码才开始在产品环境中运行。虽然是老生常谈,我们感觉,Serverless中很棒的一点就是,它强制你把代码分拆成API定义良好的小片段,这也基本保证了你的代码一开始就是可测试的。
下面,我们对Lambda在使用中给一些建议:
成果展示
几点思考
Revvel团队简介
Revvel团队的前身是前Hulu CEO Jason Kilar和CTO Richard Tom创立的短视频创业团队Vessel。Verizon在2016年11月收购了Vessel团队来服务与它在数字媒体业务方面的战略。Revvel团队主要专注在下一代互联网电视产品和服务。它和雅虎和收购的AOL一起隶属于Verizon旗下新成立的名为“Oath”的新公司。Revvel总部位于旧金山,其在北京的研发团队位于清华科技园附近,专注在大数据平台,搜索和个性化推荐技术,移动和网页开发,以及多媒体编码技术等领域。
LiveVideoStack招募全职技术编辑和社区编辑
LiveVideoStack是专注在音视频、多媒体开发的技术社区,通过传播最新技术探索与应用实践,帮助技术人员成长,解决企业应用场景中的技术难题。如果你有意为音视频、多媒体开发领域发展做出贡献,欢迎成为LiveVideoStack社区编辑的一员。你可以翻译、投稿、采访、提供内容线索等。
本文分享自 LiveVideoStack 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!