本文来自时任云帆加速创始人/CTO扶凯在LiveVideoStackCon 2017上的分享,并由LiveVideoStack整理而成,目前扶凯任南海集团下属大地零一深圳有限公司新零售业务VP。扶凯介绍了在海量视频和用户的背景下,CDN如何有效、低成本的提供服务,涉及到存储架构、边缘节点架构、流量调度等难题。
文 / 扶凯
整理 / LiveVideoStack
概览:
今天为大家分享的是与大视频时代下CDN相关的视频行业发展趋势。随着视频的内容越来越丰富,流量越来越大,视频所占用的网络带宽越来越多,以至于今年已占用网络总流量的70%~80%,而视频的玩法也花样繁多,例如大家熟悉的短视频、VR、4K等。我们可以看到视频行业已进入一个爆炸式发展的时代。在此时代下的视频网站尤其是大型视频网站,需要明确如何解决流量爆发背后隐藏的一系列亟待解决的问题:如何有效应对视频服务需求的迅猛增长?
在视频行业我们需要应对一系列问题,例如架构问题、存储问题、分发问题、转码问题等等。这些问题归根结底是什么?技术?
其实是成本问题,我们需要在控制成本的基础上为客户提供最好的服务体验以实现效益最大化。如果落实在技术上可以总结为以下几点:
在解决以上两个问题之前,需要追根溯源,首先明确视频在整个网站架构中是如何处理的,并对每一环节的成本有清晰的理解。
1、 存储与访问
例如:用户是将视频通过基于HTML5分块上传的方式发送到线上;接下来通过音视频分离的编码对用户上传的视频进行处理,并通过有AI技术来审核视频,对视频中的不良内容进行侦测……在众多处理流程中最麻烦的是存储,为什么呢?以UGC网站为例,任何一个视频,无论时长与内容,UGC网站都需要将此视频的每一份拷贝单独存储。随着视频拍摄设备的硬件发展,视频的清晰度与码率越来越高,一个视频文件大小动辄几百MB甚至上GB,而这样的文件经过转码依照不同的码流至少需要存储2~3份拷贝,以至于对现如今的视频网站而言将这些文件存储在同一个机房十分困难。例如一份文件有几十个PB,任何一个机房都无法满足如此极端的存储需求,此时我们只能将这些文件分散存储在多个机房,那具体该如何分散存储呢?
1.1 分布式存储
当用户将视频文件上传完毕后,会将文件存储在至少三个上层机房中的一个,而每一个文件可能存储在不同的几个上层中。一般的超大型视频网站会使用推送机制将至少6份文件拷贝存储在全国所有的机房当中。例如上图A、B、C三个存储中心分布在全国各地,简而言之这就是一个超大的对象分布式文件系统。
在这样一个超大的分布式文件系统中,系统会将存储单元进行分层,并根据算法将最热门的文件分发到最边缘的节点。此时便解决了存储的问题,接下来需要解决的是访问问题。
1.2 分层访问逻辑
关于访问,采用的是冷热分层的访问逻辑。既然边缘节点无法存储太多数据,那么必须采用一种高效的访问机制以分担存储的压力。我们会直接将冷门的文件调度至上层,而在边缘将热门的文件直接传送给最近的用户;直接从上层获取一部分完整的冷门文件,而热门文件则从边缘获取。这样我们便妥善解决了存储与分发问题,也就解决了存储空间和用户访问速度的二难问题。
但此时还需要解决的是推送热门文件的选择与数量。这是一个比较麻烦的问题,推送的文件, 因为不是全量, 所以无论我怎么样推送的热门算法,其实都有部分请求访问到上层,上层可能是异地,所以用户的访问体验质量可能不好。 例如小的运营商,象歌华都得透穿出来访问到上层。 原因二是用户喜好的地理差异性,例如北京的用户喜欢看的内容与上海的用户喜欢看的内容存在明显差别,而使用通用算法得出的热门是大家普遍喜欢的,无法针对不同地域特点进行个性化精准调整。之前使用了推的机制,那这里能否反向思考,使用拉的机制来妥善解决以上问题,而CDN的出现可以说很好地解决了这个问题。
2、 用户体验:大视频时代
2.1 标准CDN结构与补充
上图是一个标准的CDN结构,也就是当最边缘的用户访问最近的节点之后,继续访问上层存储;在经过第三层节点后对流量进行回源。这里需要做的第一件事是使用空间换取流量:尽可能使用最边缘节点里的空间来存储用户访问的文件从而换取吐出给用户的 80% 的流量,但由于边缘的空间有限,我们无法对其进行无限扩张。因此所做的第二件事便是使用回源来换取存储空间。假设某个文件超过一个月都未被访问的话便使其访问回源,重新取一份文件。以上便是典型的CDN结构。此时需要注意的是因为CDN中的回源操作对地域的作用,如果某个用户属性有明显的地域差异,便可以将具有地域特征的文件缓存到相应的边缘。此时相似地域特征的用户就近访问同一边缘节点,得到符合地域特征要求的文件。
我们通过使用商业CDN进行补充的方式解决了存在地域特点的视频文件分发难题,现在主流的超大型视频网站都是基于以上方案。既然谈到了CDN的整个结构,那么下面就看看如何使用CDN的单节点(边缘节点)结构来解决存储与速度的问题,这也是与之前提到的存储和体验直接相关的两个关键性问题。
2.2 CDN边缘节点结构
整个边缘节点架构基于一台具有良好批量管理性能的定制OSPF交换机。这种交换机本身就是一个集群,它可以连接到下层所有交换机,来进行批量控制。并且当机器出现宕机时可在4层路由上就迅速屏蔽宕机信息。每一台机器分为两个部分:控制部分与OCT的Cache软件。控制部分进行逻辑处理以对CDN公司的海量客户控制管理和功能逻辑处理,例如请求过来以后是从路径中一部分中计费,还是 URL 的参数中的一个字段来计费。最开始时CDN公司对用户逻辑处理的的通用做法是使用C代码将这些逻辑集成到 Cache 中是一体的。所以配置更新时,任何一个用户修改, 会需要升级整个 Cache 软件并重加载,这便导致了无数配置文件的积累。而使用分离的二块抽象,有了前端逻辑处理的部分,当使用Edge Control控制所有的用户逻辑与域名访问控制,便可简化配置文件。此时我们只需要让 Cache 只负责存储文件与视频处理等工作,其余都可以交给EdgeControl系统来完成,只需在必要时与系统进行简单的通讯,可以秒级生效全网的配置。另一个问题,为了应对海量的文件与视频存储,整个存储资源池中所有的机器都使用一致的哈希的算法并确保整个文件在节点中只存储一份。也许这里会有人质疑,如果某个视频文件的访问量非常高,存储一份会为内网大环境带来压力。尤其对于一些大型视频网站来说这是个很常见的问题,例如当上线某个热门的电视剧视频会为内网带来极大的压力,在这里我们使用一项被称为“热点迁移”的技术。这是一项非常简单的技术,我们直接在 Edge Control中,使用一个队列,对视频文件进行分析、排序再调整则无法从容应对流量短时间内的爆发性增长。而“热点迁移”技术实际是对每个URL进行排序,当某个URL出现的频率达到某一阀值时我们就会将这个热门URL扩散在多台机器上并使其以极快的速度扩展,这样就避免了大数据分析从而能够在第一时间对某个热门文件的流量爆发做出反应与干预。
2.3 配置软件
以上描述的是单机结构,接下来让我们看看Cache软件本身需要什么。我们的 Cache软件类似于Nginx的结构,正常的CDN公司大部分是基于Squid进行修改,但Squid存在很多问题,例如无法共享存储,基于 Epoll只能依托单CPU进程执行等等;即使3.0版本可在多CPU,但执行但执行效率也非常低下。而我们自己的 Cache 软件类似于ATS 直接支持多 cpu 共享存储,不过,原生的 ATS 有什么问题,就是ATS的锁的机制,会让运维和研发人员在慢的时候,或异常的时候,不知道什么时间,代码什么地方,莫名其妙会出现卡住的问题。我们的 Cache 本身就可以象它一样多进程多 CPU 上执行,中间通过epoll实现一些异步操作,而所有的共享操作通过 IPC 通信来进行。除此之外我们在自己的 Cache 软件上开发了自己的文件系统:这是一个裸盘的文件系统,运维人员都不用格式化文件系统, 只需要给硬盘路径配置进去;我们也定制开发了自己的分级内存管理,不在使用操作系统本身的内存管理。因为本身的分页大小, 特别影响 Cache 对于大文件的效率。在这里我们对硬盘 IO 的优化也不同于其他厂商,其它公司是直接增加SSD的策略,我们的策略是先增加内存,才再考虑增加SSD。因为当我们使用标准操作系统的的内存来缓存分页时就会发现落到磁盘上的I/O非常多,并且不断出现缺页,这便导致读取视频文件的效率十分低下,所以我们使用了自己开发的内存管理机制。在使用上述自己开发的技术之后,整体的I/O下降了30% ~40%,并且实现缺页操作与CPU占用率的大幅降低。
2.4 Cache软件
接下来详细介绍文件系统。传统文件系统的一台机器连接多个硬盘,一般为12个。如果一个热门视频文件访问量非常高,那么存储这个文件的当前硬盘,的使用率可达到100%,而其它几个硬盘则处在空闲状态,使得文件的访问性能十分低下。因此我对整个文件系统进行调整,将文件分成多个很小的块,以这种方式将所有文件分块存储至文件系统中,使得每个硬盘中存储的是一个孤立的文件分块,所有文件按照逻辑一体,物理上分块来进行存储与读取。这种方块存储具有以下优势:一、没有大量的I/O分布在一个盘上。因为一旦一个文件块访问量高,便意味着整个系统访问会慢,分块后此时所有磁盘的I/O是一致的一样高;二、一旦其中某个硬盘坏掉,受影响的只是文件的某一小部分的分块, 而不会是所有的整个文件,此时只需要从上层服务器重新读取文件并放置在其他正常运行的硬盘上,而不用对所有文件进行重新回源。三、如果用户在访问时需要跳过视频文件的片头片尾,那么分块存储可不存储开头与结尾,并在处理时可以按分块进行并发:例如在浏览视频时我们拖动视频至某一特定进度,正常情况下如果不将整个文件加载完成,视频服务器便无法实现正常播放;而如果使用分块存储那么只需获取文件第1MB的Meta信息,重新跳转至需要的视频进度位置并立即合成一个新的文件,极大提高视频的拖动效率。四、当删除一个文件时只需要将文件从内存列表中删去而不需要调整I/O。综上所述,自主开发文件系统可以为我们在CDN领域的开发节省很多成本。以目录刷新为例,目录刷新一直是CDN界的难题。假设需要对一百万个文件进行目录刷新,这里便存在两个问题:
1、如何找到这些URL文件?
2、如何高效处理数百万个URL文件?
解决方案是对每个文件确定一个版本号,假设所有文件目录的版本号为0,当有某个刷新请求提交过来时把此路径下所有文件的请求标成一个新的版本号,假设为1;这样当此请求发送至刷新系统中时系统便知道这个请求对应需要版本号为1的文件。此时所有的刷新操作不需要存储任何的URL到内存中, 并用删除时也不会出现集中的I/O的占用,因为仅当用户访问时系统才会进行I/O操作。
2.5 定制的业务语言
以上描述了在多种功能下如何实现有效配置,方案便是分离配置并对每一项设定专门的逻辑语言。在 CDN 的应用场景中,用户的逻辑千奇百怪,为了提高开发效率我们开发了一套定制的业务语言。此语言可实现通用的基本操作,如对URL与一些基本参数的调整操作。由于此语言的存在,运维人员不需要单独开发而只需要根据描述文档就能实现多项功能。这便相当于一个配置文件,当提交此文件生成操作之后,会进行一次编译并生成一个二进制代码,此代码会被直接传输至所有机器中,便实现了所有功能在边缘的生效。此语言还可以保证良好的性能,例如可在进行编译时将多个执行点相同的文件合并为同一个文件,或把多个路径前缀/后缀相同的文件合成为同一个文件;也可基于编译器对开发过程与业务流程进行优化,例如将多个域名相同处理流程进行合并等。
2.6 流量调度
如果想保证视频的质量,也就需要考虑基于成本与质量的流量调度,实际上我们公司也会对流量调度进行质量评估。流量如果想节约成本, 需要让调度支持很多功能,抽象出来有二点,第一个做95,第二个是做保底。另一个, 就是集中的调度处理, 无论用户选择302 还是 HTTP 调度、HTTP DNS调度、DNS调度以及M3U8调度等,都是相同的处理逻辑, 只有前端接口不一样,所以是统一体。 另外, 我们边缘化来计算所有我们的调度请求,我们会将以上所有调度直接指定到离用户最近的节点上,所以所有的机器都能实现调度, 也能实现 CDN 本身的功能。在我们在流量调度的处理算法上全部使用自主开发的一致性算法,与在上层节点使用的一致性哈希算法相同。这样上层就算变成下层, 也能很方便的保证命中率, 和不增加存储空间。
2.7 边缘化调度
一般厂商会选择使用中心节点/调度处理,在此模型下所有用户必须先请求调度才可得到目标地址,而这种动态请求需要中心*服务器实时处理,无法在边缘对其进行配置,并且服务器的机位与处理能力有限,如果有攻击,和高并发流量,极易造成调度的宕机。所以我们尝试了新的思路,即边缘化调度:不设立调度中心服务器,将边缘作为调度服务器。采用本地就近处理的方式让用户访问就近的调度器,而调度器会区分调度请求与用户访问请求并反馈不同的操作。
2.8 其他常见问题
2.8.1 回源
这是一个经典场景,边缘的用户请求最近的节点并回源。在此过程中, 如果本地的服务器异常,网络不通,这时周边没有服务怎么办?我们的结构中, 上层和下层基本是一样的,任何一个边缘节点都可作为上层与下层,并且程序, 访问, 计费本身是抽象出来,并不需要区分上下层来单独处理。只需在后台对流量进行调整或自动识别某个流量是边缘流量还是回源流量。
2.8.2 安全体系
在安全领域我们也做了很多尝试,例如WAF安全体系,可实现动态加载防盗链、内容加密与视频防盗播、文件防篡改、HTTPs回源与加密支持、防劫持等。并且采用积分机制,例如某个不良请求命令10分,某个处于黑名单中的IP 10分,当达到一定分数时安全体系会直接拒绝操作。
3、 未来CDN方向
众所周知,CDN的成本越来越低,如果想把CDN做得更好,或者想进一步挖掘CDN的潜能,必须寻找差异化路线。例如P2P解决方案;另一条路是安全解决方案,例如各种抗DDOS服务、流量清洗的服务、Wap等服务。
边缘计算
在这里我想强调的是边缘计算。大家都将CDN视为一个静态的东西,那么为什么不能将其作为一个通用的网关接口呢?因为CDN离用户最近并可实现很多功能,可以利用CDN开发很多智能解决方案,例如对多家客户的IP进行重合度分析;利用大数据技术结合自己的连接数、I/O等进行校验来实现自主学习的安全防护从而实现故障自主检测等。
举一个边缘计算的例子,假设上图是一个标准视频网站架构中的一部分。如果我要访问一个视频,需要从调度器的相关系统, 来查询很多信息,例如媒体系统、会员系统、视频调度系统等。其中大部分的信息是不怎么变的,即使只有一两个信息变化也需要客户访问原站并获取此调度器,这也就使得此调度器非常容易出现重复访问,大量并发。为了解决这个问题我们可将这三个接口在CDN层进行合并,直接缓存基本的视频原信息、回源原信息等不变信息,而只把最终的调度信息传递给用户。每次只需要在边缘与后端的客户交换少量必要信息,利用有限的服务器资源实现更稳定高效的数据交换,这是CDN一项很重要的趋势。