优化内存密集型数据流管道的 GCP 成本

Optimising GCP costs for a memory-intensive Dataflow Pipeline

我们希望降低 运行在 GCP 数据流中使用特定 Apache Beam 管道(Python SDK)的成本。

我们构建了内存密集型 Apache Beam 管道,每个执行器需要大约 8.5 GB 的内存 运行。 t运行sformation DoFn.setup 方法中当前加载了一个大型机器学习模型,因此我们可以为数百万用户预先计算推荐。

现有 GCP Compute Engine 机器类型的 memory/vCPU 比例低于我们的要求(每个 vCPU 最多 8GB RAM)或更高的比例(每个 vCPU 24GB RAM): https://cloud.google.com/compute/docs/machine-types#machine_type_comparison

我们使用 GCP m1-ultramem-40 机器类型成功 运行 此管道。然而,硬件使用——因此,成本——是次优的。此机器类型的比率为每个 vCPU 24 GB RAM。当将它用于 运行 所述管道时,虚拟机使用的可用内存不到 36% - 但是,正如预期的那样,我们为此付出了全部代价。

当尝试使用 custom-2-13312 机器类型(2 个 vCPU 和 13 GB RAM)运行 同一管道时,Dataflow 崩溃,并出现错误:

   Root cause: The worker lost contact with the service.

在监控 Compute Engine 实例时 运行 执行数据流作业时,很明显它们 运行 内存不足。 Dataflow 尝试将模型加载到内存中两次 - 每个 vCPU 一次 - 但可用内存只够一个。

如果我们能够通知 Apache Beam/Dataflow 特定的 t运行sformation 需要特定数量的内存,问题就会得到解决。但是我们没有设法找到实现这一目标的方法。

我们可以想到的另一个解决方案是尝试更改每个 Compute Engine VM 的数据流执行器的比率。这将使我们能够找到一个比率,在该比率下我们将浪费尽可能少的 vCPU,同时尊重管道内存要求。在使用前面提到的 custom-2-13312 机器类型时,我们尝试使用以下配置 运行 管道:

  1. --number_of_worker_harness_threads=1 --experiments=use_runner_v2
  2. --experiments=no_use_multiple_sdk_containers --experiments=beam_fn_api
  3. --sdk_worker_parallelism=1

使用 (1) 时,我们设法拥有一个线程,但 Dataflow 为每个 VM 生成了两个 Python 执行程序进程。这导致管道崩溃,因为当只有一个足够 space 时,尝试将模型加载到内存两次。

使用 (2) 时,每个 VM 生成一个 Python 进程,但它 运行 使用两个线程。这些线程中的每一个都尝试加载模型,并且 VM 运行s 内存不足。 方法 (3) 的结果与 (1) 和 (2) 非常相似。

无法组合多个这些配置。

是否会有(一组)配置允许我们控制每个 VM 的数据流执行器数量?

是否有任何其他方法可以降低我们可能没有的成本?

我不认为目前有一个选项可以控制每个 VM 的执行程序数量,似乎最接近的方法是使用选项 (1) 并假设 Python 每个核心执行者。

Option (1)

--number_of_worker_harness_threads=1 --experiments=use_runner_v2

为了补偿您需要的 cpu-mem 比率,我建议使用 custom machines with extended memory。这种做法应该更cost-effective.

例如,在 n1-standard-4 机器上 运行 单个执行器和单个线程的成本(4 CPUs - 15GB)将大约增加 30%比 运行 使用 custom-1-15360-ext(1 CPU - 15GB)自定义机器的相同工作负载贵。

我们正在研究 long-term 这些问题的解决方案,但这里有一个战术修复可以防止您在方法 1 和 2 中看到的模型重复:

在 VM 中跨工作人员共享模型,以避免它在每个工作人员中重复。 使用以下实用程序 (https://github.com/apache/beam/blob/master/sdks/python/apache_beam/utils/shared.py),它在 Beam 2.24 中开箱即用 如果您使用的是早期版本的 Beam,只需将 shared.py 复制到您的项目并将其用作用户代码。