准备视频服务以承受数百Gbps的负载。Yandex报告

经典CDN-任意播,GeoDNS,带有缓存的Web服务器-适用于简单文件和少量用户。但是,如果需要分发流视频,事情将变得更加有趣。一个会话会持续数十分钟,而不是一个简短的请求。没有适当的用户和内容平衡,就无法生存:没有足够的现金来支付所有费用,而且当俄罗斯与西班牙对抗时,每个人都希望立即收看。视频流平台开发负责人Andrey Vasilenkov表示,由于这一点,我们的CDN使我们能够同时为成千上万的用户会话提供服务,并体验服务器和数据中心的中断。作为奖励,他以身作则,展示了现代流行文化如何干扰学习。





- 你好!我将告诉您,当您需要为每秒数百吉比特甚至几兆兆比特的负载准备服务时,必须解决哪些问题。我们在2018年为FIFA世界杯转播做准备时首先遇到了这样的问题。



让我们从什么是流协议以及它们如何工作开始-最肤浅的概述选项。







任何流协议都基于清单或播放列表。这是一个小型文本文件,其中包含有关内容的元信息。它描述了内容的类型-直播或VoD广播(视频点播)。例如,在直播中是足球比赛或在线会议(如我们现在所拥有),在VoD方面,您的内容是预先准备好的,位于服务器上,可以分发给用户。同一文件描述了内容的持续时间,即有关DRM的信息。







它还描述了内容变体-视频轨道,音频轨道,字幕。视频轨道可以用不同的编解码器表示。例如,任何设备都支持通用H.264。有了它,您可以在家中的任何熨斗上播放视频。或者,有更现代,更高效的HEVC和VP9编解码器,可让您通过HDR支持传输4K。



音轨也可以采用不同的编解码器以不同的比特率呈现。并且其中可能还包括其中的几种-电影的原始音频音轨,英语翻译成俄语,中间影音,或者例如直接从体育馆录制体育赛事而没有评论员。







玩家如何处理所有这些?播放器的任务首先是选择可以播放的内容的各种变化,这仅仅是因为并非所有编解码器都是通用的,也不是所有的编解码器都可以在特定设备上播放。



之后,他需要选择视频和音频的质量,然后从中开始播放。他可以根据网络状况(如果知道)或基于一些非常简单的启发式方法来执行此操作。例如,以低质量开始播放,如果网络允许,则缓慢提高分辨率。



同样在此阶段,他选择将从其开始播放的音轨。假设您的操作系统中有英文。然后,他可以选择默认的英语音轨。也许它将为您带来更多便利。



之后,它开始形成到视频和音频段的链接。实际上,这些是常规的HTTP链接,与Internet上的所有其他方案相同。然后开始下载视频和音频片段,将它们依次放入缓冲区并无缝播放。这样的视频片段通常长2、4、6秒,根据您的服务可能长达10秒。







在设计CDN时,我们需要考虑哪些重点?首先,我们有一个用户会话。



我们不能只是给用户一个文件而忘记那个用户。他经常回来,并将新的和新的片段下载到他的缓冲区。



在这里重要的是要了解服务器响应时间也很重要。如果我们正在实时显示某种实时广播,则我们不能仅仅因为用户希望尽可能接近实时观看视频而建立一个较大的缓冲区。原则上,缓冲区不能太大。因此,如果服务器在用户有时间查看内容的同时没有时间响应,则视频将在某个时间点冻结​​。另外,内容非常重量级。全高清1080p的标准比特率是3-5 Mbps。因此,在一台千兆服务器上,您不能同时为200个以上的用户提供服务。这是理想的情况,因为通常情况下,用户在一段时间内不会平均地遵循其请求。







用户通常在什么时候与您的CDN互动?交互主要发生在两个地方:播放器下载清单(播放列表)时和下载片段时。



我们已经讨论过清单,这些清单是小的文本文件。此类文件的分发没有特别的问题。如果需要,请至少从一台服务器分发它们。如果它们是细分受众群,那么它们就构成了您流量的大部分。我们将讨论它们。



我们整个系统的任务减少到了这样一个事实:我们想要形成到这些段的正确链接,并在那里替换某些CDN主机的正确域。此时,我们使用以下策略:在播放列表中,立即为用户提供所需的CDN主机。这种方法没有很多缺点,但是有一个重要的细微差别。您需要确保有一种机制可以在播放过程中将用户无缝地从一台主机转移到另一台主机,而不会中断观看。实际上,所有现代流协议都具有此功能,HLS和DASH均支持此功能。细微差别:尽管在标准中存在,但即使在非常流行的开源库中,这种可能性也常常没有实现。我们自己必须将分发包发送到Shaka开源库,它是Javascript,用于网络播放器,用于播放DASH。



当您使用一个域并将其分配给所有链接时,还有另一种方案-Anycast方案。在这种情况下,您无需考虑任何细微差别-放弃一个域,每个人都很高兴。 (...)







现在让我们谈谈如何形成链接。



从网络的角度来看,任何大型公司都被组织为一个自治系统,通常甚至没有一个。实际上,自治系统是IP网络和路由器的系统,由单个运营商控制,并通过Internet与外部网络一起提供单个路由策略。 Yandex也不例外。 Yandex网络也是一个自治系统,与其他自治系统的通信是在Yandex数据中心外部的存在点进行的。 Yandex的物理电缆,其他操作员的物理电缆到达了这些存在点,并在现场通过铁设备进行了交换。正是在这样的时候,我们才有机会放置一些服务器,硬盘驱动器,SSD。这是我们将引导用户流量的地方。



我们将这组服务器称为位置。在每个这样的位置,我们都有一个唯一的标识符。我们将使用它作为此站点上主机域名的一部分,并唯一地标识它。



Yandex中有数十个这样的站点,其中有数百台服务器,并且有来自多个运营商的链接到达每个位置,因此我们也有大约数百个链接。



我们将如何选择将特定用户发送到哪个位置?







此阶段没有太多选择。我们只能使用IP地址进行决策。一个单独的Yandex Traffic Team可以为我们提供帮助,该团队了解公司中流量和网络的运作方式,而她是其他运营商的路由收集者,以便我们可以在平衡用户的过程中使用此知识。



它使用BGP收集一组路由。我们不会详细讨论BGP,它是一种协议,它允许网络参与者在其自治系统的边界处宣布其自治系统可以服务的路由。流量小组收集所有这些信息,汇总,分析并构建整个网络的完整地图,我们将其用于平衡。



我们从流量小组收到了一组IP网络和链接,可以通过这些网络和链接为客户提供服务。接下来,我们需要了解哪个IP子网适合特定用户。







我们以一种非常简单的方式进行此操作-我们构建了前缀树。然后,我们的任务是使用用户的IP地址作为密钥来查找哪个子网与该IP地址最匹配。







当我们找到它时,我们有一个链接列表,它们的权重,并且通过链接我们可以唯一地确定将用户发送到的位置。







这个地方的重量是多少?此度量标准使您可以管理不同位置的用户分布。例如,我们可以具有不同容量的链接。我们可以在同一站点上有一个100 Gb的链接和一个10 Gb的链接。显然,我们希望将更多的用户发送到第一个链接,因为它的容量更大。该权重考虑了网络拓扑,因为Internet是互连的网络设备的复杂图形,您的流量可能会经过不同的路径,因此还必须考虑此拓扑。



确保观看用户实际如何下载数据。这可以在服务器端和客户端上完成。在服务器上,我们正在收集TCP信息日志中的用户连接,以查看往返时间。从用户方面,我们积极收集浏览器和播放器性能日志。这些性能日志包含有关如何从我们的CDN下载文件的详细信息。



如果我们对所有这些信息进行汇总分析,则可以借助这些数据来改善交通团队在第一阶段选择的权重。







假设我们选择了一个链接。我们可以在此阶段立即将用户发送到那里吗?我们不能,因为重量在很长一段时间内都是静态的,并且它没有考虑负载的任何真实动态。我们想实时确定当附近有一个优先级稍低的链接(仅加载10%)时,是否现在可以使用80%加载的链接。在这种情况下,很可能我们只想使用第二个。







在这个地方还需要考虑什么?我们必须考虑链路的带宽,了解其当前状态。它可能工作或在技术上有缺陷。或者,也许我们想将其带入服务中,例如,不让用户去那里提供服务,扩展它。我们必须始终考虑该链接的当前负载。



这里有一些有趣的细微差别。您可以在多个点(例如在网络设备上)收集有关链接加载的信息。这是最准确的方法,但是它的问题是,在网络设备上您无法获得此下载的快速更新期。例如,在Yandex中,网络设备千差万别,我们收集数据的频率不能超过每分钟一次。如果系统在负载方面相当稳定,那么这根本不是问题。一切都会很好。但是,一旦负载突然涌入,您根本就没有时间做出反应,例如,这会导致包装掉落。



另一方面,您知道向用户发送了多少字节。您可以在分发机本身上收集此信息,直接创建一个字节计数器。但这不会那么准确。为什么?



CDN上还有其他用户。我们不是使用这些点胶机的唯一服务。在我们负载的背景下,其他服务的负载并不是那么重要。但是即使在我们的背景下,它也可能非常引人注目。它们的分布不会通过我们的电路,因此我们无法控制此流量。



另一点:即使您认为在发送方计算机上,您已将流量发送到一个特定的链接,但这也不是事实,因为BGP作为协议并不能为您提供这种保证。并且有一些方法可以增加您猜测的可能性,但这是另一个讨论的主题。







假设我们计算了指标,收集了所有数据。现在,我们需要一种算法来进行平衡决策。它必须具有四个重要的属性:



-提供链接带宽。

-防止链接过载,这仅仅是因为如果您以95%或98%的速度加载了链接,则网络设备上的缓冲区将开始溢出,数据包丢弃,重新传输开始,并且用户对此一无所获。

-要警告“饮用”负载,我们稍后再讨论。

“在理想的世界中,如果我们能够学会将链接回收到我们认为正确的特定水平,那就太好了。例如,下载量占85%。







我们以以下想法为基础。我们有两类不同的用户会话。第一类是新的会话,当用户刚打开电影但还没有看任何东西时,我们正在尝试找出将电影发送到哪里。或第二类,当我们进行当前会话时,已经在链接上为用户服务,占用了带宽的特定部分,在特定的服务器上服务。



我们要和他们做什么?我们为该会话的每个此类引入一个概率值。我们将有一个称为Slowdown的值,该值确定了我们在此链接上不允许的新会话的百分比。如果Slowdown为零,则我们接受所有新会话,如果Slowdown为50%,则每个第二个会话(大致而言)都拒绝在此链接上进行。同时,我们的平衡算法将在更高级别上为该用户检查替代方案。删除是相同的,仅适用于当前会话。我们可以从其他地方的站点进行一些用户会话。







我们如何选择概率指标的价值是什么?让我们以链接负载的百分比为基础,然后我们的第一个想法是:让我们使用分段线性插值。



我们采用了这样一个函数,它具有多个折射点,并使用该函数查看系数的值。如果链接的下载级别很小,那么一切都很好,Slowdown和Drop等于0,我们让所有新用户进入。一旦负载水平超过某个阈值,我们便开始拒绝此链接上某些用户的服务。在某个时候,如果负载继续增加,我们只是停止启动新的会话。



这里有一个有趣的细微差别:当前会话在此方案中具有优先权。我认为很清楚为什么会发生这种情况:如果您的用户已经为您提供了稳定的负载模式,那么您就不想带他去任何地方,因为这样可以增加系统的动力,并且系统越稳定,我们就越容易控制它。



但是,下载量可能会继续增长。在某个时候,我们可以开始取消一些会话,甚至完全删除此链接上的负载。



正是以此形式,我们在FIFA世界杯的第一场比赛中启动了该算法。看到我们看到的图片可能很有趣。她是关于以下内容的。







即使用肉眼,外面的观察者也可以理解这里可能出了点问题,问我:“安德烈,你还好吗?”如果您是我的老板,您会在房间里跑来跑去大喊:“安德烈,我的上帝!全部回滚!归还一切!”让我们告诉你这是怎么回事。



在X轴上,时间在Y轴上,我们观察到链接负载的水平。有两个服务于同一站点的链接。重要的是要了解,此刻我们仅使用了从网络设备中删除的链路负载监视方案,因此无法快速响应负载动态。



当我们将用户发送到其中一个链接时,该链接上的流量会急剧增加。链接超载。我们减轻了负担,发现自己处在上图中看到的函数的右侧。我们开始删除旧用户,并停止输入新用户。他们需要去某个地方,然后他们当然会转到下一个链接。上次它的优先级可能较低,但现在他们将其优先级较高。



第二个链接重复相同的图片。我们急剧增加了负载,请注意链接过载,卸下负载,并且这两个链接就负载水平而言是反相的。







该怎么办?我们可以分析系统的动力学特性,注意到负载增加很大,而阻尼很小。这正是我们所做的。我们花费了当前时间,将观察窗口进入了过去几分钟(例如2-3分钟),并查看了此时间间隔内链路负载的变化量。最小值和最大值之间的差称为该链接的振荡间隔。如果此振荡间隔很大,我们将增加阻尼,从而增加Slowdown并开始运行更少的会话。







此功能与上一个功能几乎相同,但骨折较少。如果下载振荡的间隔很小,则不会添加任何extra_slowdown。并且,如果振荡间隔开始增大,则extra_slowdown会采用非零值,稍后我们会将其添加到主Slowdown中。







相同的逻辑在振荡间隔的低值下工作。相反,如果您在链接上的波动很小,那么您想让更多的用户加入,减少Slowdown,从而更好地利用您的链接。







我们还实现了这一部分。最终公式如下所示。同时,我们保证这两个值-extra_slowdown和reduce_slowdown-永远不会同时具有非零值,因此只有其中一个有效地起作用。正是这种形式使这一平衡公式在FIFA世界杯的所有顶级比赛中得以幸存。即使在最受欢迎的比赛中,她的表现也相当出色:“俄罗斯-克罗地亚”,“俄罗斯-西班牙”。在这些比赛中,我们分发了Yandex流量记录-每秒1.5 TB。我们从容应对。从那时起,公式就没有任何改变,因为自那时以来,我们的服务一直没有这种流量-直到某个时刻。



然后大流行来了。人们被送往家里坐,在家中有良好的互联网,电视,平板电脑和大量的空闲时间。提供给我们服务的流量开始有机地增长,而且速度非常快。现在,就像在世界杯期间那样,这种负荷已成为我们的日常工作。此后,我们已经与运营商进行了一些扩展,但尽管如此,我们还是开始考虑算法的下一次迭代,它应该是什么以及如何更好地利用我们的网络。







我们以前的算法的缺点是什么?我们还没有解决两个问题。我们还没有完全摆脱“锯”的负担。我们极大地改善了画面,这些波动的幅度最小,周期大大增加,这也使网络得到了更好的利用。但是不时出现的所有东西都保留了下来。我们尚未了解如何将网络利用到我们想要的水平。例如,我们不能使用该配置将所需的最大链路负载级别设置为80-85%。







对于算法的下一次迭代,我们有什么想法?我们如何设想理想的网络利用率?当您有一个地方来决定流量时,似乎可以选择其中一个有希望的领域。您将所有指标收集在一个地方,用户下载段的请求到达了那里,并且在每时每刻都有完整的系统状态时,您很容易做出决定。



但是这里有两个细微差别。首先,在Yandex中并不习惯写“共同的决策点”,这仅仅是因为在我们的负载水平和交通情况下,这样的地方很快就会成为瓶颈。



还有一个细微差别-用Yandex编写容错系统也很重要。我们通常会完全关闭数据中心,而您的组件应继续正常运行而不会出现错误且不会中断。以这种形式,实际上,这个地方变成了您需要控制的分布式系统,这比我们要解决的地方要困难得多。







我们绝对需要快速的指标。没有它们,您唯一可以避免用户痛苦的方法就是对网络的利用不足。但这也不适合我们。



如果您从较高的角度看待我们的系统,那么很明显,我们的系统是具有反馈的动态系统。我们有一个自定义负载,它是一个输入信号。人们来来去去。我们有一个控制信号-我们可以实时更改的两个值。对于具有反馈的这种动态系统,自动控制的理论已经发展了很长时间,几十年了。我们想使用它的组件来稳定我们的系统。







我们看了卡尔曼滤波器。这是一件很酷的事情,可让您建立系统的数学模型,并在嘈​​杂的度量标准或缺少某些类别的度量标准的情况下,使用实际系统来改进模型。然后基于数学模型做出有关真实系统的决策。不幸的是,事实证明我们没有很多类的指标可以使用,并且该算法无法应用。







我们从另一侧着手,以该理论的另一个组件-PID控制器为基础。他对您的系统一无所知。它的任务是了解系统的理想状态,即我们所需的负载水平,以及系统的当前状态,例如负载水平。他认为这两个状态之间的差异是一个错误,并使用他的内部算法来控制控制信号,即我们的Slowdown和Drop值。其目的是最大程度地减少系统中的错误。



我们将每天在生产中试用该PID控制器。也许再过几个月我们就能告诉您有关结果。



在这方面,我们可能会完成有关网络的工作。我非常想告诉您有关当我们已经在主机之间选择流量时如何在该位置本身内分配流量的信息。但是没有时间了。这可能是单独的大型报告的主题。







因此,在下一个系列中,您将学习如何最佳利用主机上的缓存,如何处理热流量和冷流量,热流量来自何处,内容的类型如何影响其分发算法以及哪个视频在服务上获得最高的缓存命中率,以及谁唱歌的人



我还有另一个有趣的故事。如您所知,春季开始隔离。 Yandex长期以来一直拥有一个名为Yandex.Tutorial的教育平台,该平台允许教师上传视频和课程。学生到那里观看内容。在大流行期间,Yandex开始支持学校,并积极邀请他们加入其平台,以便学生可以远程学习。在某个时候,我们看到了流量的相当不错的增长,情况也相当稳定。但是在四月的一个晚上,我们在图表上看到了类似以下内容的东西。







以下是有关教育内容的流量的图片。我们看到他在某个时候急剧下降。我们开始慌张,以了解发生了什么,发生了什么。然后,我们注意到服务的总流量开始增长。显然,发生了一些有趣的事情。



实际上,在那时,发生了以下情况。







这是男人跳舞的速度。



小小巨人音乐会开始了,所有的学生都去观看了。但是在音乐会结束后,他们返回并成功地继续学习。我们经常在我们的服务中看到此类图片。因此,我认为我们的工作很有趣。谢谢大家!我大概会以CDN结尾。



All Articles