Hulu:如何实现大型比赛直播系统自动扩容

2021-09-01 17:02:07 浏览数 (2)

Hulu 技术团队在过去的一年中,进行了大量系统准备与改进工作,期望提供更稳定,更高质量的大型比赛直播。

文/ Brandon Lonac、Raymond Khalife、Kalyani Narayanan、Travis McCann、Justin Goad

译/ 元宝

原文 https://medium.com/hulu-tech-blog/streaming-the-super-bowl-preparing-hulus-systems-and-operations-for-the-biggest-game-of-the-year-5ce10e1923f6

大约一年前在博客中,我们曾概述了如何在一些大型活动中扩展我们的实时流服务,如“March Madness”等。

从那时起,Hulu在美国的用户量已经超过了2500万,我们几乎每一次重大活动都在打破自己的并发记录。进入2019年,我们知道超级碗将再次打破纪录,所以我们不得不为今年规模最大的体育赛事做好准备 —— 取得了很大的收获:Hulu今年观看超级碗比赛现场直播的观众人数是2018年的四倍,我们成功地为观众在他们喜爱的设备上提供了稳定、高质量的大型比赛直播。

在过去的一年里,Hulu技术团队专注于三个关键领域,我们逐步完善了准备工作的整体方案:

  • 改进负载预测:提高我们为任何特定事件准确预测系统负载的能力。
  • 快速扩展我们的系统:按需增强关键系统,或者在没有选择的情况下提供冗余。
  • 战争游戏和战术准备:改进为大型电视直播活动做准备的最佳实践。

利用历史收视率数据改进并发预测

今年,我们利用上个赛季的数据来预测并发收视率。通过获取历史收视率数据,并将其与用户增长估计相结合,我们能够对每周的并发性预测进行建模。在整个2018-2019赛季,我们的估计与实际相比有 /- 10%的错误率。我们还构建了一个并发收视率矩阵,并将其推断为关键路径系统的每秒请求数。结合这两种新功能,我们可以更好地了解什么系统需要扩展、扩展多少以及何时扩展。

该模型给出了预测的最小、最大和平均范围的置信区间。当我们接近实际日期时,置信区间会变得更小,直到得到这样的结果:

使用混合云的方法扩展我们的平台

Hulu的大部分服务都运行在内部PaaS上,我们称之为Donki,它利用了数据中心的Apache Mesos / Aurora和云中的容器编排系统。Donki将服务打包成容器,相同的容器可以在我们的数据中心和云中运行。虽然我们最近将部分最高流量服务迁移到了云中,但我们能够在可能的故障转移方案中利用我们的数据中心。Donki允许我们根据特定服务的需要轻松地将部署协调到任一环境中。我们专注于利用云中的自动扩展功能来更好地处理意外的流量激增,从而保持我们的系统良好运行。

我们利用自动扩展的两种方式:

  • 扩展承载服务的集群。
  • 扩展服务本身。

承载服务的集群可以通过添加或删除计算机来自动扩展。自动扩展必须根据规则进行,它是根据CPU和内存预留阈值来收缩或增长。

服务本身将通过添加或删除实例来自动扩展,具体取决于每个实例的每分钟请求数、每个实例的CPU使用率或每个实例的内存使用量等指标。我们的生产工程团队负责可观察性和模拟(混乱),他们运行负载测试来发现每个实例的容量,并与团队合作设置适当的自动伸缩规则。

我们需要扩展的关键服务领域之一是支持用户发现体验的堆栈。我们采用了灵活的方法,根据流量预测和自动化的定期性能测试来扩展系统,以逐步加载和加速整个端到端堆栈。为了帮助服务团队做到这一点,我们的生产准备小组提供了两个功能:

1. 适用于具有真实测试模拟的团队的负载测试工具。

2. 在整个服务堆栈中协调端到端的压力测试。

这是一项巨大的工作,它解放了团队,使他们能够专注于特定的扩展需求。

我们的系统具有不同的架构域,这些域需要单独或整体进行扩展。我们从压力测试开始,找到这些领域和整个系统的弱点。这导致了一个中断/修复周期,因为我们巩固了系统的每个域。自动化系统范围的测试每周运行多次。这允许快速迭代验证在以前的运行中发现的团队修复。各个团队还能够独立地对其服务进行压力测试,以便在运行更大规模测试之前验证改进。由于域中的所有服务都使用Donki(我们的PaaS),因此很容易对每个应用程序集群的大小进行微调。然后,工作可以集中在应用程序优化和调整应用程序集群和规模参数上。

一旦系统能够处理预期的负载,我们就开始进行峰值测试,以模拟大量用户在游戏开始时登录或模拟播放失败。

不同的域以不同的方式扩展。探索体验侧重于个性化、元数据丰富的响应。在向数百万用户扩展时,这可能会出现问题。目标是在那个时刻为用户提供最好的响应。我们专注于缓存基线响应,然后在此基础上进行个性化,以确保查看者找到他们想要的内容。我们从头开始对系统进行了功能降低。为了实现系统所需的规模,我们做出了这些架构设计决策。

1. 使用异步/非阻塞应用程序框架

2. 使用断路器、限速和减载模式

3. 同时使用本地和分布式缓存

4. 内聚客户端行为

我们的API网关和边缘服务使用的是基于JVM的异步事件驱动的应用程序框架和断路器。这允许一次针对单个应用程序实例打开数千个连接。如果太多的请求保持打开时间太长,就会导致内存压力。所有应用程序都处于无响应的状态。我们使用压力和峰值测试来微调对系统的速率限制请求,以保护系统免受过多流量的影响。这允许系统在极端尖峰期间继续运行,并为用户提供自动,而不是在压力下崩溃并且不为任何人服务。如果用户流量超出了我们的速率限制,我们的系统将开始减轻负载。如果需要丢弃请求,我们的API层中的断路器将跳闸并将请求发送到后备集群。这是我们核心客户端应用程序体验的高度缓存版本,支持对我们唯一用户的请求。Discovery Experience的主要目标是返回响应,这种模式组合有助于确保这一点。

为了实现低延迟响应和大规模的Discovery Experience,缓存是非常依赖的。节点既使用基于本地JVM的缓存,也使用分布式缓存。节点缓存响应基于MRU和TTL的元数据。在缓存丢失或删除的情况下,将从分布式缓存中获取数据。这种对不同缓存的组合使用有助于使Fallback体验几乎与正常响应几乎没有区别。

这将我们带到最后一点,即客户行为的内聚力。使用定义的和一致的服务器API,客户端也可以帮助扩展。考虑到HTTP响应代码和报头,客户端可以帮助防止在错误情况下进行轰击,并在错误场景中生成更多的负载。在过去,我们已经看到了各种客户机中不一致的错误处理逻辑可以做什么。在调用API时使用指数级后退和可变时间量等策略是客户端可以帮助扩展的简单方法。这似乎是一种合理的方法,但它需要与我们拥有的众多客户协同努力。它还需要关于API应该多久进行通信的最佳实践。

准备故障转移流以实现运营准备和冗余

我们花了很多时间对系统进行压力测试和扩展,但事情并不总是按照计划进行。这就是为什么我们总是计划冗余,特别是在视频播放等关键领域,这也是我们系统的核心,我们的目标是确保源流本身的最高可用性。基于内容合作伙伴,源流路径的架构可能大不相同,并且每个工作流本身都面临着不同的挑战。因此,确保为实时流实现多个故障转移选项是绝对有必要的。

实施这些额外的信号通路需要与我们的信号提供商和合作伙伴密切合作。我们遵循的一些最佳实践是为实时流建立多个非交叉信号路径,确保故障转移脚本经过了充分的测试,并且可以在几秒钟内执行源流之间的切换,并保留实时和DVR体验为确保用户在故障转移时没有任何问题。

除了为大型活动做好准备所涉及的所有技术之外,为我们的组织做好准备也至关重要。随着我们的规模不断扩大,我们采用的一项新举措是,在压力测试故障情景下定期进行桌面练习,以帮助团队更好地准备和从潜在的中断中恢复。Wargaming已被证明是一个非常有教育意义的过程,可以建立一个持续运营的准备文化,并确保我们的Runbook全部搞定。这种做法还揭示了我们需要为更多的失败情景制定缓解计划。我们确定了许多团队所需的短期和长期工作,我们将继续跟踪这些团队的未来。

超越超级碗——使我们的准备工作自动化

我们一直在提高我们为大型活动提供服务的严谨性和纪律性。整个技术组织的团队花费了无数的时间来准备我们的系统,以供越来越多的观众使用。

我们得到的一些关键结论是:

  • 通过自动化我们的生产负载测试,我们能够建立始终做好准备的一致性并进一步推动自己。
  • 持续改进我们的预测确实有助于推动团队需要提供的结果。
  • 通过为负载测试提供一个中央平台,我们解放了工程师的精力,让他们专注于如何更好地架构和重构系统以适应规模。

这些努力的结果让人们对今年的超级碗更加有信心,但这个过程仍然涉及一些手动元素随着2019年剩余时间的推进,我们计划将更多时间用于自动化和这些领域的改进。最终,我们希望我们的预测能够自动优化容量预测,以考虑更多的变量。我们还计划将负载测试更多地集成到我们的CI / CD管道中,并在一致的基础上扩展我们测试的场景,以获得更好的可靠性。尽管大型活动可能总会有一些疏忽,但我们的目标是尽可能多地准备和自动化,以使得我们的团队更有效率和过程更加简化。

0 人点赞