#google-cloud-platform #google-cloud-dataflow #apache-beam
#google-cloud-platform #google-cloud-поток данных #apache-beam
Вопрос:
Мы хотим снизить затраты на запуск конкретного конвейера Apache Beam (Python SDK) в потоке данных GCP.
Мы создали конвейер Apache Beam с интенсивным использованием памяти, для запуска которого на каждом исполнителе требуется примерно 8,5 ГБ оперативной памяти. В настоящее время большая модель машинного обучения загружена в метод преобразования DoFn.setup
, поэтому мы можем предварительно вычислить рекомендации для нескольких миллионов пользователей.
Существующие типы компьютеров GCP Compute Engine имеют либо меньшее соотношение памяти и vCPU, чем требуется (до 8 ГБ ОЗУ на vCPU), либо гораздо большее соотношение (24 ГБ ОЗУ на vCPU):https://cloud.google.com/compute/docs/machine-types#machine_type_comparison
Мы успешно запустили этот конвейер, используя тип машины GCP m1-ultramem-40
. Однако использование оборудования — и, следовательно, затраты — были неоптимальными. Этот тип компьютера имеет соотношение 24 ГБ оперативной памяти на vCPU. При его использовании для запуска указанного конвейера виртуальные машины использовали менее 36% доступной памяти — но, как и ожидалось, мы заплатили за все это.
При попытке запустить тот же конвейер с использованием custom-2-13312
типа компьютера (2 vCPU и 13 ГБ ОЗУ) произошел сбой потока данных с ошибкой:
Root cause: The worker lost contact with the service.
При мониторинге экземпляров Compute Engine, выполняющих задание потока данных, было ясно, что им не хватает памяти. Dataflow дважды пытался загрузить модель в память — один раз на vCPU — но доступной памяти хватило только на один.
Если бы мы могли сообщить Apache Beam / Dataflow, что для конкретного преобразования требуется определенный объем памяти, проблема была бы решена. Но нам не удалось найти способ достичь этого.
Другим решением, которое мы могли придумать, было попытаться изменить соотношение исполнителей потоков данных на виртуальную машину Compute Engine. Это позволило бы нам найти соотношение, при котором мы тратили бы как можно меньше 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) нам удалось создать один поток, но поток данных породил два процесса-исполнителя Python на виртуальную машину. Это привело к сбою конвейера, поскольку была предпринята попытка загрузить модель в память дважды, когда было достаточно места только для одной.
При использовании (2) для каждой виртуальной машины создавался один процесс Python, но он выполнялся с использованием двух потоков. Каждый из этих потоков пытался загрузить модель, и виртуальной машине не хватало памяти. Подход (3) имел результат, очень похожий на (1) и (2).
Было невозможно объединить несколько из этих конфигураций.
Существует ли (набор) конфигураций, которые позволили бы нам контролировать количество исполнителей потока данных на виртуальную машину?
Существуют ли какие-либо другие альтернативы для снижения затрат, которых у нас может и не быть?
Комментарии:
1. У меня такая же проблема (я думаю). Как вы проверили использование памяти в задании? вкладка «Показатели работы» показывает только загрузку процессора?
2. Я профилировал память в экземплярах compute engine, которые запускали конвейер. Простой способ сделать это — подключиться к виртуальным машинам и использовать
top
. Делая это, вы должны быть в состоянии видеть, как доступная память уменьшается до тех пор, пока у виртуальной машины больше не останется доступной памяти и она не будет уничтожена.3. Не могли бы вы пояснить, почему было невозможно объединить эти конфигурации? Я думаю, что конфигурация
--number_of_worker_harness_threads=1 --experiments=use_runner_v2 --experiments=no_use_multiple_sdk_containers
должна привести к 1 контейнерному процессу SDK на виртуальную машину, выполняющую 1 поток, который обрабатывает работу, независимо от количества ядер ЦП, но наличие пользовательской виртуальной машины с 1 ядром ЦП может быть более экономичным, как указано в другом ответе, если только ваш код не выходит из GIL (например, через библиотеку C , такую как TensorFlow) и фактически использует все доступные ядра.
Ответ №1:
Мы работаем над долгосрочными решениями этих проблем, но вот тактическое исправление, которое должно предотвратить дублирование модели, которое вы видели в подходах 1 и 2:
Разделите модель в виртуальной машине между рабочими, чтобы избежать ее дублирования на каждом рабочем месте. Используйте следующую утилиту (https://github.com/apache/beam/blob/master/sdks/python/apache_beam/utils/shared.py ), который доступен из коробки в Beam 2.24 Если вы используете более раннюю версию Beam, скопируйте только shared.py к вашему проекту и используйте его в качестве пользовательского кода.
Ответ №2:
Я не думаю, что на данный момент есть возможность контролировать количество исполнителей на виртуальную машину, кажется, что самое близкое, что вы получите, — это использовать опцию (1) и предположить, что исполнитель Python на ядро.
Вариант (1)
--number_of_worker_harness_threads=1 --experiments=use_runner_v2
Чтобы компенсировать необходимое вам соотношение cpu /mem, я бы предложил использовать пользовательские компьютеры с расширенной памятью. Этот подход должен быть более экономичным.
Например, стоимость запуска одного исполнителя и одного потока на n1-standard-4
компьютере (4 процессора — 15 ГБ) будет примерно на 30% дороже, чем выполнение той же рабочей нагрузки с использованием custom-1-15360-ext
(1 процессор — 15 ГБ) пользовательской машины.
Комментарии:
1. Как люди могут создавать пользовательские машины? на странице, на которую вы ссылаетесь, объясняется, что делать во время создания экземпляра или после создания экземпляра (требуется перезагрузка), но для потока данных вам нужно указать тип экземпляра при запуске задания, и поток данных позаботится о жизненном цикле экземпляра.
2. Вы можете указать пользовательский тип компьютера при запуске конвейера, например
--workerMachineType=custom-1-15360-ext
3. Как создать пользовательскую машину?
4. Как вы упомянули, для потока данных вы не создаете машины заранее, а скорее указываете, какой тип машины вы хотите использовать. Тип машины для пользовательских типов машин на основе семейства n1 построен следующим образом: пользовательский-[NUMBER_OF_CPUS]-[NUMBER_OF_MB].
ext
Флаг для расширенной памяти, а также как создать пользовательский компьютер на основе других семейств, объясняется здесь , в частности, посмотрите наgcloud
раздел инструкций5. Я думаю, что NUMBER_OF_MB должен быть кратен 256.