博客
2024/02/05
幕后花絮:为高流量流式环境中的 Apache Beam 打造自动扩展器
Apache Beam 作业自动扩展器设计简介
欢迎来到我们关于使用 Beam 和 Flink 构建可扩展、自管理流式基础设施的博客系列的第三部分,也是最后一部分。在我们的上一篇博文中,我们深入探讨了我们流式平台的规模,重点介绍了我们管理超过 40,000 个流式作业并每秒处理超过 1000 万个事件的能力。这种令人印象深刻的规模为我们今天要解决的挑战奠定了基础:动态流式环境中资源分配的复杂任务。
在这篇博文中,Talat Uyarer(架构师/高级首席工程师)和 Rishabh Kedia(首席工程师)将更详细地介绍我们的自动扩展器。想象一下,你的流式系统被不断变化的工作负载淹没。我们的案例提出了一项独特的挑战,因为我们的客户配备了分布在全球各地的防火墙,在一天中的不同时间生成日志。这导致工作负载不仅随时间变化,而且还由于 PANW 设置的更改或新网络安全解决方案的添加而随着时间推移而升级。此外,我们的代码库的更新需要在所有流式作业中推出更改,导致系统处理未处理的数据时,需求暂时激增。
传统上,管理这种需求的涨落涉及手动、通常效率低下的方法。人们可能会过度配置资源以处理峰值负载,不可避免地会导致在非高峰时段浪费资源。相反,更注重成本的策略可能涉及在高峰时段接受延迟,并期望稍后追赶。但是,这两种方法都需要不断监控和手动调整 - 远非理想情况。
在这个时代,Web 前端的自动扩展是理所当然的,我们渴望将同样的效率和自动化应用于流式基础设施。我们的目标是开发一个系统,该系统可以动态跟踪并调整我们流式操作的工作负载需求。在这篇博文中,我们将向您介绍我们的创新解决方案 - 专为 Apache Beam 作业设计的自动扩展器。
为清楚起见,在本上下文中,当我们提到“资源”时,指的是处理流式管道的 Flink 任务管理器或 Kubernetes Pod 的数量。这些任务管理器不仅仅与 CPU 相关;它们还涉及 RAM、网络、磁盘 I/O 和其他计算资源。
但是,我们的解决方案以某些假设为前提。首先,它针对的是处理大量数据量的操作。如果您的工作负载只需要几个任务管理器,那么此系统可能不是最佳选择。在我们的案例中,我们有 10,000 多个工作负载,并且每个工作负载都有不同的工作负载。手动调整对我们来说不是一种选择。我们还假设数据是均匀分布的,允许通过添加更多任务管理器来提高吞吐量。这个假设对于有效的水平扩展至关重要。虽然现实世界中的复杂性可能会挑战这些假设,但对于本次讨论的范围,我们将重点关注满足这些条件的场景。
加入我们,深入了解我们的自动扩展器的设计和功能,这是一个旨在将效率、适应性和一点智能引入流式基础设施世界的解决方案。
识别自动扩展的正确信号
当我们监督 Flink 上的 Apache Beam 作业之类的系统时,识别关键信号至关重要,这些信号可以帮助我们了解工作负载与资源之间的关系。这些信号是我们的指路明灯,向我们展示何时落后或浪费资源。通过准确识别这些信号,我们可以制定有效扩展策略并实时实施更改。想象一下,需要从 100 个任务管理器扩展到 200 个任务管理器 - 我们如何平稳地进行过渡?这就是这些信号发挥作用的地方。
请记住,我们的目标是找到适用于任何工作负载和管道的通用解决方案。虽然特定问题可能受益于独特的信号,但我们在这里的重点是创建一个一刀切的方法。
在 Flink 中,任务构成基本执行单元,由一个或多个运算符组成,例如映射、过滤或减少。Flink 通过尽可能将这些运算符链接到单个任务来优化性能,从而最大限度地减少诸如线程上下文切换和网络 I/O 之类的开销。你的管道在经过优化后将变成阶段的定向无环图,每个阶段根据你的代码处理元素。不要将阶段与物理机器混淆 - 它们是独立的概念。在我们的作业中,我们使用 Apache Beam 的 `backlog_bytes` 和 `backlog_elements` 指标来衡量积压信息。
向上扩展信号
积压增长
让我们举一个实际的例子。考虑一个从 Kafka 读取数据的管道,其中不同的运算符处理数据解析、格式化和累积。这里的关键指标是吞吐量 - 每个运算符随着时间的推移处理的数据量。但仅仅依靠吞吐量是不够的。我们需要检查每个运算符的队列大小或积压。不断增加的积压表明我们落后了。我们将其衡量为积压增长 - 积压大小随时间的变化率,突出了我们的处理赤字。
积压时间
这将我们引向了积压时间,这是一个衍生指标,将积压大小与吞吐量进行比较。它衡量了在假设没有新数据到达的情况下,清除当前积压需要多长时间。这有助于我们根据特定的处理需求和阈值来确定特定大小的积压是否可以接受或有问题。
向下扩展:少即是多
CPU 利用率
向下扩展的一个关键信号是 CPU 利用率。低 CPU 利用率表明我们使用的资源比必要的多。通过监控这一点,我们可以有效地缩减规模,而不会影响性能。
信号摘要
总之,我们为有效自动扩展确定的信号是
- 吞吐量:我们性能的基线。
- 积压增长:表明我们是否跟上传入数据的速度。
- 积压时间:有助于了解积压的严重程度。
- CPU 利用率:指导我们在资源优化方面。
这些信号看似简单,但它们的简单性是可扩展、与工作负载无关的自动扩展解决方案的关键。
简化 Flink 上 Apache Beam 作业的自动扩展策略
在 Flink 上运行 Apache Beam 作业的世界中,决定何时扩展或缩减规模就像在繁忙的厨房里做厨师一样。你需要密切关注几种成分 - 你的工作负载、虚拟机 (VM) 以及它们之间的相互作用。这是关于保持完美的平衡。我们的主要目标?避免在处理过程中落后(没有积压增长)、确保任何现有的积压都是可管理的(积压时间短)并有效地使用我们的资源(例如 CPU)。
向上扩展:跟上和追赶
想象一下,你的系统就像一个共同工作的厨师团队。以下是我们如何决定何时将更多厨师带入厨房(即向上扩展)
跟上:首先,我们查看当前团队规模(VM 数量)以及他们的处理量(吞吐量)。然后,我们根据传入订单的数量(输入速率)调整团队规模。这是为了确保我们的团队规模足以应付当前的需求。
追赶:有时,我们可能会有积压的订单。在这种情况下,我们决定我们需要多少额外厨师才能在所需时间内(例如 60 秒)清除此积压。策略的这部分有助于我们迅速重回正轨。
扩展示例:实践视角
让我们用一个例子来描述一下。最初,我们有稳定的订单流(输入速率),与我们的处理能力(吞吐量)相匹配,因此没有积压。但突然,订单增加,我们的团队开始落后,产生积压。我们通过增加团队规模来应对新的订单速率。虽然积压没有进一步增长,但它仍然存在。最后,我们给团队添加了一些厨师,这使我们能够快速清除积压并恢复到新的平衡状态。
向下扩展:何时减少资源
向下扩展就像知道何时让一些厨师在高峰时段过后休息一下。我们会在以下情况下考虑这一点
- 我们的积压很低 - 我们已经追赶上了订单。
- 积压没有增长 - 我们正在跟上传入的订单。
- 我们的厨房(CPU)没有太辛苦 - 我们正在有效地使用我们的资源。
向下扩展是关于在不影响服务质量的情况下减少资源。这是为了确保在高峰时段结束后,我们没有人员过剩。
总结:有效扩展的秘诀
总之,我们的扩展策略是,对于向上扩展,我们首先确保积压排空时间超过阈值(120 秒)或 CPU 超过阈值(90%)
积压增加,即积压增长 > 0
积压持续,即积压增长 = 0
总结
要向下扩展,我们需要确保机器利用率很低(< 70%)并且没有积压增长,当前积压排空时间小于限制(10 秒)。
因此,向下扩展后计算所需资源的唯一驱动因素是 CPU。
执行自动扩展决策
在我们的设置中,我们使用 Reactive Mode,它使用 Adaptive Scheduler 和 Declarative Resources manager。我们希望将资源与插槽对齐。正如大多数 Flink 文档中建议的那样,我们为每个 vCPU 插槽设置一个。我们大多数作业使用 1 vCPU 4GB 内存组合来进行任务管理器。
Reactive Mode 是 Adaptive Scheduler 的一项独特功能,它遵循每个集群一个作业的原则,这是在 Application Mode 中执行的规则。在此模式下,作业配置为利用集群内的所有可用资源。添加任务管理器将增加作业的规模,而移除资源将减少作业的规模。在此设置中,Flink 自行管理作业的并行性,始终最大程度地提高并行性。
在重新缩放事件期间,Reactive 模式会使用最新的检查点重新启动作业。这消除了创建保存点的需求,通常用于手动作业重新缩放。重新缩放后重新处理的数据量受检查点间隔(我们为 10 秒)的影响,恢复所需的时间取决于状态的大小。
调度器确定作业中每个操作符的并行度。此设置不可用户配置,任何针对单个操作符或整个作业的设置尝试都将被忽略。
并行度只能通过为管道设置最大值来影响,调度器将遵守该最大值。我们的 maxParallelism 受管道将处理的总分区数以及作业本身的限制。我们通过 maxWorker 计数限制 TaskManager 的最大数量,并通过设置 maxParallelism 控制作业在 shuffle 中的键计数。此外,我们为每个管道设置 maxParallelism 来管理管道并行度。作业在工作程序方面不能超过作业的 maxParallelism。
在自动缩放分析之后,我们将标记作业是否需要向上缩放、无操作或向下缩放。为了与作业交互,我们使用了一个基于 Flink Kubernetes Operator 构建的库。该库允许我们通过简单的 Java 方法调用与我们的 Flink 作业进行交互。库将我们的方法调用转换为 Kubernetes 命令。
在 Kubernetes 世界中,向上缩放的调用将如下所示
kubectl scale flinkdeployment job-name --replicas=100
Apache Flink 将处理向上缩放所需的其余工作。
使用自动缩放维护有状态流式应用程序的状态
为自动缩放调整 Apache Flink 的状态恢复机制涉及利用其强大的功能,如最大并行度、检查点和自适应调度器,以确保高效且弹性的流式处理,即使系统动态调整以适应不同的负载。以下是这些组件在自动缩放环境中如何协同工作
- 最大并行度为作业可以扩展的程度设置上限,确保状态可以在更多或更少的节点之间重新分配,而不会超过预定义的边界。这对自动缩放至关重要,因为它允许 Flink 有效地管理状态,即使任务槽的数量发生变化以适应不同的工作负载。
- 检查点是 Flink 容错机制的核心,它定期将每个作业的状态保存到持久性存储(在我们的例子中是 GCS 存储桶)。在自动缩放场景中,检查点使 Flink 能够在缩放操作后恢复到一致的状态。当系统扩展(添加更多资源)或缩减(删除资源)时,Flink 可以从这些检查点恢复状态,确保数据完整性和处理连续性,而不会丢失关键信息。在缩减或扩展情况下,可能需要一段时间才能从最后一个检查点重新处理数据。为了减少该数量,我们将检查点间隔缩短到 10 秒。
- Reactive 模式是自适应调度器的一种特殊模式,它假设每个集群只有一个作业(由应用程序模式强制执行)。Reactive 模式配置作业,使其始终使用集群中可用的所有资源。添加 TaskManager 将扩展您的作业,删除资源将缩减作业。Flink 将管理作业的并行度,始终将其设置为可能的最大值。当作业进行调整大小时,Reactive 模式会使用最新的成功检查点触发重新启动。
结论
在本博客系列中,我们深入研究了在高容量流式环境中为 Apache Beam 创建自动缩放器的过程,重点介绍了从概念化到实现的旅程。这项工作不仅解决了动态资源分配的复杂性,而且为流式基础设施的效率和适应性设定了新的标准。通过将智能缩放策略与 Apache Beam 和 Flink 的强大功能相结合,我们展示了一种可扩展的解决方案,该解决方案优化了资源使用并保持了不同负载下的性能。该项目证明了团队合作、创新和前瞻性流式数据处理方法的力量。随着本系列的结束,我们对所有贡献者表示感谢,并期待这项技术的不断发展,邀请社区加入我们进行进一步的讨论和发展。
参考资料
[1] Google Cloud Dataflow 中的流式自动缩放 https://www.infoq.com/presentations/google-cloud-dataflow/
[2] 管道生命周期 https://cloud.google.com/dataflow/docs/pipeline-lifecycle
[3] Flink 弹性缩放 https://nightlies.apache.org/flink/flink-docs-master/docs/deployment/elastic_scaling/
致谢
这是为新基础设施构建并从云提供商管理的流式基础设施迁移大型客户基于应用程序到自管理的 Flink 基于基础设施的规模化工作。感谢 Palo Alto Networks CDL 流式团队,他们帮助实现了这一目标:Kishore Pola、Andrew Park、Hemant Kumar、Manan Mangal、Helen Jiang、Mandy Wang、Praveen Kumar Pasupuleti、JM Teo、Rishabh Kedia、Talat Uyarer、Naitik Dani 和 David He。
探索更多
加入我们的 社区 进行讨论并分享您的经验,或在 GitHub 上为我们正在进行的项目做出贡献。您的反馈非常宝贵。如果您对本系列有任何意见或问题,请随时通过 用户邮件列表 与我们联系。
请继续关注我们,获取更多有关 Apache Beam、Flink 和 Kubernetes 的更新和见解。