优化内存密集型数据流管道的 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
机器类型时,我们尝试使用以下配置 运行 管道:
--number_of_worker_harness_threads=1 --experiments=use_runner_v2
--experiments=no_use_multiple_sdk_containers --experiments=beam_fn_api
--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 复制到您的项目并将其用作用户代码。
我们希望降低 运行在 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
机器类型时,我们尝试使用以下配置 运行 管道:
--number_of_worker_harness_threads=1 --experiments=use_runner_v2
--experiments=no_use_multiple_sdk_containers --experiments=beam_fn_api
--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 复制到您的项目并将其用作用户代码。