Развертывание и запуск кода Python на облачных кластерах.
Делиться

Это вторая часть моей серии из двух статей о библиотеке Ray, фреймворке Python, созданном AnyScale для распределенных и параллельных вычислений. В первой части я рассказывал о том, как распараллелить ресурсоемкие задачи Python на локальном ПК, распределив нагрузку по всем доступным ядрам, что привело к значительному улучшению времени выполнения. Ссылку на первую часть я оставлю в конце этой статьи.
В этой части рассматривается аналогичная тема, но мы выводим распределение рабочих нагрузок Python на новый уровень, используя Ray для их распараллеливания в многосерверных кластерах в облаке.
Если вы дочитали до этого места, не ознакомившись с первой частью, то вкратце о Ray можно сказать следующее: это платформа для распределенных вычислений с открытым исходным кодом. Разработанная для упрощения масштабирования программ на Python от ноутбука до кластера с минимальными изменениями в коде. Уже одного этого, надеюсь, будет достаточно, чтобы вас заинтересовать. В собственном тесте на своем настольном ПК я взял простую, относительно несложную программу на Python, которая находит простые числа, и сократил время ее выполнения в 10 раз, добавив всего четыре строки кода.
Где можно запускать кластеры Ray?
Сетевые кластеры лучей можно настроить на следующих платформах:
- AWS и GCP Cloud, хотя существуют и неофициальные интеграции с другими провайдерами, такими как Azure.
- AnyScale — это полностью управляемая платформа, разработанная создателями Ray.
- Kubernetes также можно использовать через официально поддерживаемый проект KubeRay.
Предварительные требования
Чтобы следовать моему процессу, вам потребуется предварительно настроить несколько вещей. Для демонстрации я буду использовать AWS, поскольку у меня там уже есть аккаунт; однако я ожидаю, что настройка для других облачных провайдеров и платформ будет очень похожей. Вам потребуется:
- Учетные данные настроены для выполнения команд Cloud CLI от выбранного вами поставщика.
- VPC по умолчанию и как минимум одна связанная с ней публичная подсеть, имеющая общедоступный IP-адрес.
- Файл с парой SSH-ключей (.pem), который вы можете загрузить на свой локальный компьютер, чтобы Ray (и вы) могли подключаться к узлам в вашем кластере.
- У вас достаточно квот для удовлетворения запрошенного количества узлов и виртуальных процессоров в любом настроенном вами кластере.
Если вы хотите провести локальное тестирование вашего кода Ray перед развертыванием в кластере, вам также потребуется установить библиотеку Ray. Это можно сделать с помощью pip.
$ pip install ray
Я буду запускать всё из оболочки WSL2 Ubuntu на своём компьютере с Windows.
Чтобы убедиться в правильности установки Ray, вы можете использовать его интерпретатор командной строки. В окне терминала введите следующую команду.
$ ray —help Использование: ray [OPTIONS] COMMAND [ARGS]… Параметры: —logging-level TEXT Пороговый уровень логирования, choices=['debug', 'info', 'warning', 'error', 'critical'], по умолчанию='info' —logging-format TEXT Формат логирования. default=»%%(asctime)st%%(levelname)s %%(filename)s:%%(lineno)s — %%(message)s» —version Показать версию и выйти. —help Показать это сообщение и выйти. Команды: attach Создать или подключиться к SSH-сессии кластера Ray. check-open-ports Проверить открытые порты в локальном кластере Ray. cluster-dump Получить данные логов с одного или нескольких узлов. … … …
Если вы этого не видите, значит, что-то пошло не так, и вам следует еще раз проверить вывод команды установки.
Если всё в порядке, то мы можем ехать.
И ещё один важный момент. Создание ресурсов, таких как вычислительные кластеры, у облачного провайдера, например AWS, влечет за собой затраты , поэтому крайне важно это учитывать. Хорошая новость в том, что в Ray есть встроенная команда, которая удалит любую созданную вами инфраструктуру, но для большей безопасности следует дважды проверить, не остались ли по ошибке «включенными» какие-либо неиспользуемые и потенциально дорогостоящие сервисы.
Наш пример кода на Python
Первый шаг — модифицировать существующий код Ray из части 1 для работы на кластере. Вот исходный код для вашего означения. Напомним, что мы пытаемся подсчитать количество простых чисел в определенном числовом диапазоне.
import math import time # —————————————— # Изменение № 1 # —————————————— import ray ray.init() def is_prime(n: int) -> bool: if n < 2: return False if n == 2: return True if n % 2 == 0: return False r = int(math.isqrt(n)) + 1 for i in range(3, r, 2): if n % i == 0: return False return True # ----------------------------------------- # Изменение № 2 # ----------------------------------------- @ray.remote(num_cpus=1) # цикл на чистом Python → 1 CPU на задачу def count_primes(a: int, b: int) -> int: c = 0 for n in range(a, b): if is_prime(n): c += 1 return c if __name__ == «__main__»: A, B = 10_000_000, 20_000_000 total_cpus = int(ray.cluster_resources().get(«CPU», 1)) # Начало «блокового» режима; Мы можем выполнить перебор позже. chunks = max(4, total_cpus * 2) step = (B — A) // chunks print(f»nodes={len(ray.nodes())}, CPUs~{total_cpus}, chunks={chunks}») t0 = time.time() refs = [] for i in range(chunks): s = A + i * step e = s + step if i < chunks - 1 else B # ----------------------------------------- # Изменение № 3 # ----------------------------------------- refs.append(count_primes.remote(s, e)) # ----------------------------------------- # Изменение № 4 # ----------------------------------------- total = sum(ray.get(refs)) print(f"total={total}, time={time.time() - t0:.2f}s")
Какие изменения необходимы для запуска в кластере? Ответ прост: требуется всего одно незначительное изменение .
Замените ray.init() на ray.init(address=auto)
В этом и заключается одно из преимуществ Ray. Один и тот же код работает практически без изменений на вашем локальном компьютере и в любом другом месте, где вы захотите его запустить, включая большие многосерверные облачные кластеры.
Настройка нашего кластера
В облаке кластер Ray состоит из головного узла и одного или нескольких рабочих узлов. В AWS все эти узлы представляют собой просто экземпляры EC2. Кластеры Ray могут иметь фиксированный размер или автоматически масштабироваться вверх и вниз в зависимости от ресурсов, запрашиваемых приложениями, работающими в кластере. Сначала запускается головной узел, а рабочие узлы настраиваются с использованием адреса головного узла для формирования кластера. Если включено автоматическое масштабирование, рабочие узлы автоматически увеличиваются или уменьшаются в зависимости от нагрузки приложения и уменьшаются через заданный пользователем период (по умолчанию 5 минут).
Ray использует YAML-файлы для настройки кластеров. YAML-файл — это просто текстовый файл с синтаксисом, похожим на JSON, используемый для конфигурации системы.
Вот YAML-файл, который я буду использовать для настройки кластера. Я обнаружил, что ближайший к моему настольному ПК экземпляр EC2 по количеству ядер процессора и производительности — это c7g.8xlarge . Для простоты я использую тот же тип сервера, что и все рабочие узлы, но при желании можно комбинировать разные типы EC2.
cluster_name: ray_test provider: type: aws region: eu-west-1 availability_zone: eu-west-1a auth: # Для образов Amazon Linux AMI пользователь SSH — 'ec2-user'. # Если вы переключитесь на образ Ubuntu AMI, измените это значение на 'ubuntu'. ssh_user: ec2-user ssh_private_key: ~/.ssh/ray-autoscaler_eu-west-1.pem max_workers: 10 idle_timeout_minutes: 10 head_node_type: head_node available_node_types: head_node: node_config: InstanceType: c7g.8xlarge ImageId: ami-06687e45b21b1fca9 KeyName: ray-autoscaler_eu-west-1 worker_node: min_workers: 5 max_workers: 5 node_config: InstanceType: c7g.8xlarge ImageId: ami-06687e45b21b1fca9 KeyName: ray-autoscaler_eu-west-1 InstanceMarketOptions: MarketType: spot # ========================= # Команды настройки (запускаются на головном сервере + рабочих серверах) # ========================= setup_commands: — | set -euo pipefail have_cmd() { command -v «$1» >/dev/null 2>&1; } have_pip_py() { python3 -c 'import importlib.util, sys; sys.exit(0 if importlib.util.find_spec(«pip») else 1)' } # 1) Убедитесь, что Python 3 присутствует if ! have_cmd python3; then if have_cmd dnf; then sudo dnf install -y python3 elif have_cmd yum; then sudo yum install -y python3 elif have_cmd apt-get; then sudo apt-get update -y sudo apt-get install -y python3 else echo «Не найден поддерживаемый менеджер пакетов для установки python3.» >&2 exit 1 fi fi # 2) Убедитесь, что pip существует if ! have_pip_py; then python3 -m ensurepip —upgrade >/dev/null 2>&1 || true fi if ! have_pip_py; then if have_cmd dnf; then sudo dnf install -y python3-pip || true elif have_cmd yum; then sudo yum install -y python3-pip || true elif have_cmd apt-get; then sudo apt-get update -y || true sudo apt-get install -y python3-pip || true fi fi if ! have_pip_py; then curl -fsS https://bootstrap.pypa.io/get-pip.py -o /tmp/get-pip.py python3 /tmp/get-pip.py fi # 3) Обновите инструменты для работы с пакетами и установите Ray python3 -m pip install -U pip setuptools wheel python3 -m pip install -U «ray[default]»
Ниже приведено краткое объяснение каждого важного раздела YAML.
cluster_name: Присваивает имя кластеру, позволяя Ray отслеживать и управлять им отдельно от других. provider: Указывает, какое облако использовать (здесь AWS), а также регион и зону доступности для запуска экземпляров. auth: Определяет, как Ray подключается к экземплярам по SSH — имя пользователя и закрытый ключ, используемые для аутентификации. max_workers: Устанавливает максимальное количество рабочих узлов, до которых Ray может масштабироваться при необходимости увеличения вычислительных ресурсов. idle_timeout_minutes: Указывает Ray, как долго ждать перед автоматическим завершением работы простаивающих рабочих узлов. available_node_types: Описывает различные типы узлов (головной и рабочие), их размеры экземпляров, образы AMI и ограничения масштабирования. head_node_type: Определяет, какой из типов узлов выступает в качестве контроллера кластера (головной узел). setup_commands: Перечисляет команды оболочки, которые выполняются один раз на каждом узле при его первом создании, обычно для установки программного обеспечения или настройки среды.
Для начала создания кластера используйте команду `ray` в терминале.
$ ray up -y ray_test.yaml
Ray выполнит свою работу, создав всю необходимую инфраструктуру, и через несколько минут вы должны увидеть что-то подобное в окне терминала.
… … … Следующие шаги Чтобы добавить еще один узел в этот кластер Ray, выполните команду `ray start —address='10.0.9.248:6379'`. Чтобы подключиться к этому кластеру Ray: `import ray ray.init()`. Чтобы отправить задание Ray с помощью CLI заданий Ray: `RAY_ADDRESS='http://10.0.9.248:8265'`. `ray job submit —working-dir . — python my_script.py`. Дополнительную информацию об отправке заданий Ray в кластер Ray см. на странице https://docs.ray.io/en/latest/cluster/running-applications/job-submission/index.html. Чтобы завершить работу среды выполнения Ray, выполните команду `ray stop`. Чтобы просмотреть состояние кластера, используйте команду `ray status`. Чтобы отслеживать и отлаживать Ray, просмотрите панель мониторинга по адресу 10.0.9.248:8265. Если подключение к панели мониторинга не удается, проверьте настройки брандмауэра и конфигурацию сети. Соединение с IP-адресом 108.130.38.255 закрыто. Новый статус: up-to-date. Полезные команды: Для завершения работы кластера: ray down /mnt/c/Users/thoma/ray_test.yaml Для получения IP-адреса головного узла кластера: ray get-head-ip /mnt/c/Users/thoma/ray_test.yaml Для переадресации портов Ray Dashboard кластера на локальный компьютер: ray dashboard /mnt/c/Users/thoma/ray_test.yaml Для отправки задания в кластер переадресуйте порты Ray Dashboard в другом терминале и выполните: ray job submit —address http://localhost:
Запуск задания Ray в кластере.
На данном этапе кластер создан, и мы готовы отправить на него нашу задачу Ray. Чтобы предоставить кластеру более существенные возможности для работы, я увеличил диапазон поиска простых чисел в своем коде с 10 000 000 до 20 000 000, а затем до 10 000 000–60 000 000. На моем локальном компьютере Ray выполнил это за 18 секунд.
Я немного подождал, пока все узлы кластера полностью инициализируются, а затем запустил код на кластере с помощью этой команды.
$ ray exec ray_test.yaml 'python3 ~/ray_test.py'
Вот результат моей работы.
(base) tom@tpr-desktop:/mnt/c/Users/thoma$ ray exec ray_test2.yaml 'python3 ~/primes_ray.py' 2025-11-01 13:44:22,983 INFO util.py:389 — setting max workers for head node type to 0 Loaded cached provider configuration If you experience issues with the cloud provider, try re-running the command with —no-config-cache. Fetched IP: 52.213.155.130 Warning: Permanently added '52.213.155.130' (ED25519) to the list of known hosts. 2025-11-01 13:44:26,469 INFO worker.py:1832 — Подключение к существующему кластеру Ray по адресу: 10.0.5.86:6379… 2025-11-01 13:44:26,477 INFO worker.py:2003 — Подключено к кластеру Ray. Просмотреть панель мониторинга можно по адресу http://10.0.5.86:8265 nodes=6, CPUs~192, chunks=384 (autoscaler +2s) Совет: используйте `ray status` для просмотра подробного состояния кластера. Чтобы отключить эти сообщения, установите RAY_SCHEDULER_EVENTS=0. (autoscaler +2s) Ни один из доступных типов узлов не может выполнить запросы на ресурсы {'CPU': 1.0}*160. Добавьте подходящие типы узлов в этот кластер, чтобы решить эту проблему. Всего = 2897536, время = 5,71 с. Соединение с 52.213.155.130 закрыто.
Как видите, время выполнения на кластере составило чуть более 5 секунд. Таким образом, пять рабочих узлов выполнили ту же задачу менее чем за треть времени, которое потребовалось на моем локальном ПК. Неплохо.
После завершения работы с кластером выполните следующую команду Ray для его удаления.
$ ray down -y ray_test.yaml
Как я уже упоминал, всегда следует перепроверять свою учетную запись, чтобы убедиться, что эта команда сработала должным образом.
Краткое содержание
В этой статье, второй части серии из двух статей, показано, как запускать ресурсоемкий код Python на облачных кластерах с помощью библиотеки Ray. Распределяя нагрузку между всеми доступными виртуальными процессорами, Ray обеспечивает высокую производительность и время выполнения кода.
Я описал и показал, как создать кластер с помощью YAML-файла и как использовать интерфейс командной строки Ray для отправки кода на выполнение в кластере.
Используя AWS в качестве примера платформы, я взял код Ray на Python, который работал на моем локальном ПК, и запустил его — практически без изменений — на кластере EC2 из 6 узлов. Это показало значительное повышение производительности (в 3 раза) по сравнению с запуском вне кластера.
В заключение я показал, как использовать инструмент командной строки Ray для удаления инфраструктуры кластера AWS, созданной Ray.
Если вы еще не читали мою первую статью из этой серии, перейдите по ссылке ниже, чтобы ознакомиться с ней.
Рэй: Распределенные вычисления для всех, часть 1
Обращаю ваше внимание на то, что, помимо периодического использования их услуг, я не имею никакого отношения к AnyScale, AWS или какой-либо другой организации, упомянутой в этой статье.
Источник: towardsdatascience.com



























