Continuous batching: как повысить загрузку GPU при обслуживании LLM‑запросов
При выполнении inference в LLM генерация проходит в две стадии. Сначала идёт prefill phase: модель обрабатывает все входные токены сразу. Затем начинается decoding phase. На каждой итерации появляется один новый токен, при этом используются все ранее полученные key‑value пары.
Когда несколько пользователей отправляют запросы одновременно, системы обычно собирают их в batch и прогоняют через модель параллельно. Так GPU обрабатывает запросы сразу, а не по одному.
Самый простой вариант называется static batching. Допустим, одновременно пришло 8 запросов. Их объединяют в одну группу, заранее выделяют память GPU и продолжают обработку, пока не завершится каждый из них. Проблема возникает, если длина генерации сильно различается. Один запрос может требовать 10 токенов, другой 500. Первый закончится уже на 10-й итерации, но его слот всё равно остаётся занятым до тех пор, пока не завершится вся группа. Это называют straggler problem: самый длинный запрос фактически задаёт темп остальным. В итоге наивные системы обслуживания дают лишь 20–30% загрузки GPU даже при высокой нагрузке.
Подход continuous batching решает проблему иначе. Планирование происходит на уровне каждой итерации. Вместо фиксированной группы система пересматривает состав batch на каждом forward pass. Как только один запрос доходит до end‑of‑sequence token и генерация завершается, его слот сразу освобождается. Если в очереди есть новый запрос и хватает памяти KV cache, его подключают к обработке уже на следующей итерации.
Простой пример. Есть 8 доступных слотов и 20 ожидающих запросов. Static batching занял бы все 8 и просто ждал, пока каждый завершится. Если один запрос закончился на 10-й итерации, его слот простаивал бы до 500-й итерации самого длинного. В continuous batching всё происходит иначе. Допустим, слот 3 освободился на итерации 47. Уже на итерации 48 туда попадает новый запрос. GPU не простаивает, а состав batch меняется прямо во время вычислений.
Ключевые факты
При статическом batching несколько запросов (например, 8) объединяются и обрабатываются вместе до полного завершения всей группы.
Если один запрос в батче требует 10 токенов, а другой, 500 токенов, слот первого остаётся пустым ещё 490 итераций, пока не завершится самый длинный запрос.
В наивных системах обслуживания LLM загрузка GPU может ограничиваться уровнем 20–30% даже при высокой нагрузке.
В continuous batching планировщик пересматривает батч на каждой итерации: например, если слот освобождается на итерации 47, новый запрос может занять его уже на итерации 48.