Технологии

AWS ускорила повторный запуск AI-моделей на EKS до 93% настройками Run:ai

Крупные веса быстрее поступают из S3 в GPU, а результаты torch.compile переживают перезапуск pod: для 203 GiB модели повторный старт сократился с 463 до 32 секунд.

AWS ускорила повторный запуск AI-моделей на EKS до 93% настройками Run:ai

Холодный старт — это не одна задержка

AWS разобрала путь запуска AI inference workload на Amazon EKS и показала, что большой model server начинает обслуживать запросы лишь после двух дорогих стадий: переноса весов из Amazon S3 в память GPU и выполнения torch.compile. При стандартных настройках Run:ai Model Streamer загрузка моделей объёмом 60–200 GiB на p5.48xlarge занимала от 80 до 460 секунд.

Соотношение задержек зависит от размера модели. В измерении с 64 GiB Qwen около 29 секунд, или 35% старта, уходило на веса, а примерно 53 секунды, или 65%, — на компиляцию. Для 203 GiB Llama-4-Scout картина переворачивалась: загрузка весов занимала около 423 секунд и формировала 92% задержки, тогда как компиляция требовала около 34 секунд.

Из этого следует, что универсальной кнопки ускорения нет. Для моделей меньше примерно 100 GiB AWS считает главным bottleneck повторную компиляцию, время которой сильнее связано с архитектурой, чем с числом параметров. Для более крупных моделей доминирует почти линейно растущая передача весов, поэтому инженеры оптимизировали обе стадии независимо.

Первое решение: крупные S3 chunks вместо сотен запросов

Run:ai Model Streamer читает model shards из S3 через HTTP byte-range requests. AWS проверила размеры chunk от 256 MiB до 8 GiB и обнаружила, что диапазон от 256 MiB до 4 GiB давал близкое время — примерно 13,35–14,20 секунды, хотя требовал разного числа workers. Переход к 8 GiB, превышавшему типичный размер shard около 3,9 GiB, наоборот увеличил задержку на 56%.

Причина — реальная модель параллелизма. Один worker закрепляется за shard file, а range requests внутри этого worker выполняются последовательно. Деление файла на пятнадцать chunks по 256 MiB не создаёт пятнадцать одновременных передач: оно добавляет последовательные round trips в том же соединении. Параллельность возникает между разными файлами, поэтому 256 соединений не дали преимущества перед 17.

AWS рекомендует chunk size 4 GiB: он близок к размеру большинства SafeTensors shards и обычно сводит каждый файл к одному запросу. Дополнительно конфигурация быстро прерывает и повторяет медленную передачу, потому что готовность pod определяется самым отстающим chunk. После этих настроек веса 64 GiB модели при TP=1 загружались за 12–14 секунд без изменения кода приложения.

Второе решение: сохранять результат torch.compile

Отключать torch.compile ради быстрого старта AWS не предлагает: по её оценке, компиляция повышает inference throughput на 5–30% за счёт kernel fusion, сокращения числа kernel launches и удаления Python из горячего пути. Вместо отказа от этой оптимизации команда перенесла compile cache из эфемерной файловой системы pod на сохраняющееся хранилище узла.

По умолчанию vLLM уже кэширует скомпилированные artifacts локально, но Kubernetes уничтожает их вместе с завершившимся pod. Направление cache directories на hostPath в локальном NVMe позволяет следующему pod на том же GPU node переиспользовать результат. Первая компиляция занимает около 53 секунд и записывает примерно 15 MiB, а повторная загрузка этих artifacts требует около четырёх секунд.

Кэш привязан к сочетанию архитектуры модели и GPU, tensor-parallel degree, версий PyTorch, Triton и CUDA. Изменение этого набора приводит к новой компиляции, а одинаковые container image, GPU type и TP setting позволяют использовать сохранённый результат. Для первого pod на новом узле AWS также прототипировала pre-warming через S3, но оставила его advanced-вариантом из-за дополнительного DaemonSet и жизненного цикла bucket.

От 463 до 32 секунд на 203 GiB модели

В итоговом тесте vLLM модель объёмом 67 GiB на p5.48xlarge и TP=2 стартовала 82 секунды при базовой конфигурации. Tuning сократил загрузку весов с 29 до 12 секунд, поэтому первый запуск занял 65 секунд. При повторном запуске на том же node кэш уменьшил стадию torch.compile с 53 до четырёх секунд, а полное время — до 16 секунд, то есть на 80% относительно baseline.

Эффект для 203 GiB Llama-4-Scout при TP=4 оказался сильнее. Базовый повторный запуск занимал 463 секунды: 429 секунд на веса и 34 секунды на compile. После tuning и использования compile cache показатели составили 26 и шесть секунд соответственно — 32 секунды суммарно, или на 93% меньше исходного времени.

Первая реплика на свежем node не получает весь выигрыш от локального cache. В крупном тесте она занимала около 59–60 секунд после оптимизации, потому что compile выполнялся один раз заново; 32 секунды достигались следующими pod на том же узле. Cross-node cache pre-warming тоже давал 32 секунды с первого запуска, но это уже отдельная custom-конфигурация, а не только два базовых изменения.

Почему AWS не выбрала предварительную загрузку на NVMe

Команда сравнила прямой tuned streaming из S3 с предварительным копированием весов на NVMe через s5cmd. Для модели около 200 GB двухэтапный путь занимал примерно 45 секунд: около 25 секунд S3→NVMe и ещё 20 секунд NVMe→GPU. Прямой tuned streaming S3→GPU занимал около 25 секунд, поэтому дополнительный локальный hop не окупал усложнение.

NVMe также доступен не на всех instance types, а fallback на Amazon EBS даёт существенно меньшую пропускную способность. Региональный S3 не требует платы за transfer из EC2 в том же регионе и способен увеличивать throughput для часто используемого prefix. Поэтому AWS выбрала настройку уже интегрированного Model Streamer, которая работает не только на EKS, но также применима к EC2, ECS и SageMaker.

Практический смысл решения — в сокращении времени, когда дорогой GPU уже выделен, но endpoint ещё не принимает traffic. Это особенно заметно при autoscaling, rolling update и восстановлении pod после сбоя. Однако опубликованные цифры относятся к конкретным p5.48xlarge, моделям, TP settings и vLLM; их следует воспроизводить на собственном сочетании storage, network и accelerator, а не считать гарантированным SLA для любого кластера.

Оставшийся предел находится внутри Model Streamer

После config-only ускорения AWS измерила, что stock Run:ai во время загрузки использует лишь одно-два активных соединения из пула на 64. Контрольный опыт с одновременной отправкой всех ranges достиг 33–39 Gbps, тогда как последовательная схема дала 5,96 Gbps при сетевом интерфейсе на 40 Gbps. Ограничителем оказался calling pattern, а не сама сеть.

При TP>1 на PCIe-инстансах часть времени уходит и на NCCL broadcast: каждый rank скачивает часть файлов, после чего полная модель распространяется между ranks. Для 61 GiB модели при TP=4 такой broadcast занял 35 секунд, или 73% времени загрузки. Прямое получение каждым rank только нужных byte ranges могло бы убрать эту передачу, но потребует изменения кода Run:ai engine.

AWS прямо отделяет эти наблюдения от уже доступных улучшений. Опубликованная конфигурация — 4 GiB chunks с рассчитанной concurrency, timeout/retry и постоянный torch.compile cache — применима сейчас и не требует патча приложения. Более полное использование connection pool и отказ от лишнего broadcast остаются направлениями возможного upstream-развития, а не поставленными функциями.

Первоисточники

  1. AWS — Fast model loading for AI inference on Amazon EKS