中文翻译暂不可用,显示俄语原文。
Что такое continuous batching и как оно влияет на throughput?
Краткий тезис
batching|Continuous batching — это техника динамического управления батчами при инференсе LLM, при которой запросы добавляются и удаляются из батча после каждого шага декодирования, а не фиксируются на весь цикл генерации. В отличие от static batching, batching|непрерывный батчинг значительно повышает throughput (пропускную способность) за счёт более эффективного использования GPU, уменьшая простои, вызванные разной длиной генерации запросов. Типичный прирост throughput составляет 4–6x при одновременном снижении latency (задержки) на 30–50%.
1. Проблема статического батчинга
При static batching (статическом батчинге) сервер накапливает запросы, формирует фиксированный батч и передаёт его LLM. Батч обрабатывается последовательно шаг за шагом (итерациями декодирования), пока все запросы не сгенерируют свой ответ. Если один запрос генерирует 10 токенов, а другой — 500, GPU простаивает после завершения первого, ожидая, пока второй закончит.
- Неравномерная длина ответов ведёт к "растянутым" батчам.
- Для ускорения коротких запросов приходится ждать завершения всех.
- Возникают пустые слоты (padding), если часть запросов уже завершена.
Это снижает GPU utilization (загрузку GPU). Типичная утилизация в batching|static batching — 30–50% для real-time трафика.
2. Определение continuous batching
Continuous batching (непрерывный батчинг) — подход, при котором планировщик на каждом шаге декодирования (итерации) пересматривает состав батча:
- Запросы, сгенерировавшие End-of-Sequence (EOS), сразу удаляются.
- Освободившиеся слоты занимаются новыми запросами из очереди ожидания.
- Каждый запрос проходит свои стадии: prefill (обработка промпта) и decode (авторегрессивная генерация) независимо от других.
Таким образом, батч динамически обновляется каждую итерацию. Этот механизм называют iteration-level scheduling (планирование на уровне итераций).
3. Как работает iteration-level scheduler (на примере vLLM)
Самый известный open-source фреймворк, реализующий continuous batching — vLLM. Его планировщик работает так:
- Очередь ожидания Входящие запросы помещаются в очередь.
- Формирование батча На итерации планировщик выбирает из очереди столько запросов, сколько помещается в свободную память (ключи/значения внимания — KV cache).
- Prefill Новые запросы проходят фазу prefill (вычисление первого токена). Эта фаза выполняется эффективно как batch matrix multiplication.
- Decode: После prefill запросы переходят в фазу decode, где на каждой итерации генерируется один следующий токен.
- Завершение Как только запрос доходит до EOS или до max_tokens, он удаляется из батча; его память освобождается.
- Заполнение пустот На следующей итерации освободившиеся KV-слоты могут быть заняты новыми prefilling-запросами или дополнительными decoding-запросами.
Ключевой элемент — PagedAttention (см. вопрос о памяти), который позволяет управлять KV-кэшем блоками, а не непрерывными буферами, что облегчает динамическое добавление/удаление.
4. Влияние на throughput
Throughput (пропускная способность) — количество запросов (или токенов), обработанное системой в единицу времени.
| Фактор | Static batching | Continuous batching | Прирост |
|---|---|---|---|
| GPU Utilization | 30–50% (из-за простоя в конце) | 70–95% (почти всегда занят) | +50–100% |
| Время обработки батча | Равно макс. длине генерации | Сумма по всем итерациям, слоты не простаивают | Снижение в 2–6 раз |
| Эффективный throughput | Ограничен worst-case длиной | Приближается к average длине | +4–6x |
Причина В static batching GPU простаивает, когда часть запросов уже закончила генерацию. В continuous batching на освободившиеся слоты сразу поступают новые запросы, поддерживая высокую загрузку.
Математическая иллюстрация Пусть t<sub>i</sub> — длина генерации i-го запроса. Для static batching одного батча из N запросов время ~ max(t<sub>i</sub>) × N<sub>tok</sub>? Нет, точнее: каждая итерация занимает одно и то же время (прямой проход). Время батча = max(t<sub>i</sub>) × (время итерации). Все запросы проходят одинаковое количество шагов, равное максимальной длине. Аппаратные ресурсы используются только для активных запросов на каждом шаге.
Continuous batching убирает холостые итерации: каждый запрос обрабатывается ровно t<sub>i</sub> шагов. GPU всегда параллельно обрабатывает столько запросов, сколько помещается в память. Эффект сильнее при большом разбросе длин ответов.
5. Влияние на latency
Latency (задержка) — время от отправки запроса до получения первого или последнего токена.
- Static batching: время ожидания в очереди + время обработки батча (макс. длина). Для коротких запросов latency может быть высокой, если они попали в батч с длинными.
- Continuous batching: запросы быстрее попадают в исполнение (слоты освобождаются чаще). Средняя latency снижается на 30–50%.
- Однако для отдельных долгих запросов latency может немного возрасти из-за конкуренции с новыми запросами (но обычно это компенсируется более частым выходом токенов).
Важно Continuous batching улучшает P50/P95 latency для большинства пользователей, особенно когда нагрузка переменная.
6. Сравнение в таблице
| Характеристика | Static Batching | Continuous Batching |
|---|---|---|
| Состав батча | Фиксирован на весь цикл генерации | Меняется на каждой итерации |
| Завершение запроса | Ждёт окончания всех | Удаляется сразу после EOS |
| Добавление новых запросов | Только после завершения батча | На любой итерации (если есть место) |
| GPU Utilization | 30–50% | 70–95% |
| Throughput (отн. единицы) | 1× (базовый) | 4–6× |
| Latency (P50) | Высокая для коротких | Ниже на 30–50% |
| Сложность реализации | Низкая (простой queue) | Высокая (scheduler + управление памятью) |
| Потребление памяти (KV cache) | Фиксированный буфер под батч | Динамическое выделение (PagedAttention) |
7. Дополнительные аспекты и trade-offs
- Memory overhead Continuous batching требует более сложного управления KV-кэшем. Без PagedAttention было бы много фрагментации.
- Fairness (справедливость): Планировщик может отдавать приоритет prefilling или decoding. Некоторые схемы (например, равномерные квоты) предотвращают голодание длинных запросов.
- Preemption (вытеснение): Если память исчерпана, можно приостановить part of decoding-запросы, чтобы пропустить prefilling (или наоборот). Это ещё один уровень динамики.
- Batch formation latency На каждую итерацию планировщик тратит время на перетасовку (CPU overhead). В хорошо оптимизированных системах (vLLM) это время negligible.
- Ограничения Continuous batching плохо работает при очень маленьких батчах (1–2 запроса) — оверхед больше выгоды. Но для production с сотнями concurrent запросов — это стандарт.
8. Реализации в open-source
| Фреймворк | Механизм | Особенности |
|---|---|---|
| vLLM | Iteration-level scheduler + PagedAttention | Де-факто стандарт, легко конфигурируется |
| TensorRT-LLM | In-flight batching (аналог continuous) | Оптимизация под NVIDIA GPU, поддержка FP8 |
| LightLLM | Dynamic batching на основе очередей | Легковесная альтернатива |
| TGI (HuggingFace) | Continuous batching (через расширение) | Простая интеграция с HF models |
9. Когда continuous batching неэффективен
- Offline batch inference (например, генерация summary для корпуса): можно заранее отсортировать запросы по длине, что даёт ту же выгоду без overhead continuous batching.
- При очень малом размере батча (1–2 запроса) выигрыш незначителен.
- Если все запросы имеют одинаковую длину (синтетический сценарий), разница с static batching минимальна.
Пет-проект для закрепления
Задача Реализовать симулятор continuous batching и сравнить его throughput с static batching.
Инструменты Python + NumPy (или PyTorch для более реалистичной модели времени).
Шаги:
- Модель симуляции (mock LLM): Каждый запрос имеет случайную длину генерации (например, от 10 до 500 токенов). Время одной итерации decode = constant (0.1 ms), Prefill = пропорционально числу входных токенов (0.2 ms / токен).
- Static batching:
- Накопить N запросов (например, 128).
- Запустить batch: выполнить prefills, затем decode min(max_len) шагов.
- Замерить общее время. Перейти к следующему batch.
- Continuous batching:
- Очередь запросов и динамический батч размером до max_batch_size (например, 64).
- На каждом шаге: обработать prefills (если есть новые запросы) и decode всех активных.
- Удалять завершённые.
- Собирать статистику.
- Сравнение
- Throughput = ∑ длины / total_time.
- Latency (время от начала до конца каждого запроса) — гистограмма.
- Эксперименты
Ожидаемый результат Симулятор покажет, что continuous batching даёт throughput в 2–5 раз выше, особенно при высоком разбросе длин, а P50 latency снижается. Код можно выложить на GitHub с визуализацией.
Связь с другими вопросами
| Вопрос | Тема |
|---|---|
| 201 | Основная идея continuous batching (этот вопрос — углубление) |
| 840 | Архитектура инференс-энжинов (vLLM) |
| 841 | PagedAttention и управление KV-cache (ключевая зависимость) |
| 842 | Scheduling policies (FCFS, priority, SLO) |
| 845 | Throughput vs latency trade-offs |
| 846 | Distributed inference и tensor parallelism |
Навигация
- Предыдущий: 842
- Следующий: 844
- Индекс: 00. Индекс разборов