Суть открытия: изоляция планировщика
Авторы статьи на Towards Data Science разобрали заявления Anyscale о 23-кратном ускорении vLLM. Выяснилось, что этот результат складывается из трех факторов: более быстрый движок, управление KV-cache и сам планировщик. Проведя контролируемый эксперимент, где менялся только алгоритм планирования, автор доказал, что continuous batching дает прирост до 2.91x по сравнению со статическим батчингом. Общий прирост от перехода от «голых» HuggingFace Transformers к vLLM составил 3.86x на тестовом оборудовании.
Почему Decode не замедляется от размера батча
Ключевой инсайт заключается в природе шага декодирования (decode). В отличие от префилла (prefill), который обрабатывает промпт за один проход, декодирование требует чтения весов модели на каждом шаге. Для модели Qwen2.5-7B-Instruct (15.2 GB в bfloat16) чтение весов занимает ~55.7 мс теоретически. На практике:
- При батче 1 шаг занимает 78.05 мс.
- При батче 32 шаг занимает 74.77 мс (в среднем).
Это означает, что GPU тратит одно и то же время на чтение весов, независимо от того, сколько последовательностей обрабатывается. Увеличение батча с 1 до 32 дало рост общей пропускной способности в 26.7x, при этом задержка между токенами (inter-token gap) осталась практически неизменной. «Грузовик» едет с одинаковой скоростью, просто везет больше груза.
Сравнение политик батчинга
Эксперимент проводился на 8 запросах с разной длиной вывода (от 2 до 12 шагов) и 4 слотами GPU. Разница в эффективности стала очевидной:
| Политика | Принцип работы | Результат (на примере 32 запросов) |
|---|---|---|
| Static | Ждет завершения всех запросов в батче, прежде чем начать следующий. Слоты простаивают, если один запрос длиннее других. | 32 шага. 42.9% времени слотов простаивает. При разбросе длин до 700 токенов — до 91% простоя. |
| Dynamic | Добавляет таймаут: батч отправляется, если очередь не заполнилась за время T. Решает проблему задержки входа, но не простоя слотов внутри батча. | Улучшает latency входа, но слоты все равно могут простаивать после завершения коротких запросов. |
| Continuous | Планировщик проверяет завершение последовательностей после каждого шага декодирования и мгновенно заполняет освободившиеся слоты новыми запросами. | 26 шагов. 0% простоя слотов. Освободившиеся слоты сразу используются, а не ждут конца «медленного» запроса. |
Компромисс: Latency vs Throughput
Непрерывный батчинг имеет свою цену. При батче 32 время ожидания первого токена (TTFT) для нового запроса выросло с 121 мс (при батче 1) до 2.8 секунд. Это связано с очередью и префиллом. Однако, как только поток токенов начался, скорость доставки не упала. Эффективная пропускная способность на один запрос снизилась с 12.76 до 10.66 токенов/с (на 16%), но это падение произошло до начала стриминга, а не во время него.
Вывод для разработчиков
Основной вывод: вариативность длины вывода (output-length variation) — главный враг эффективности. Continuous batching (как в vLLM или Orca) позволяет «заполнять дыры» в расписании GPU, что критически важно для продакшн-серверов, где запросы имеют разную сложность. Статический батчинг оставляет GPU простаивать, пока один «тяжелый» запрос не завершится, тогда как непрерывный подход держит GPU загруженным на 100% за счет ротации запросов.
Источник: Towards Data Science ↗
