localaiforum
Войти
Руководство › Запуск и обслуживание

Батчинг и несколько пользователей

По одному запросу за раз начинается каждая десктопная сессия — и это сжигает GPU впустую. Вся игра обслуживания — батчинг: заставить один проход по весам обслуживать много запросов сразу. Эта страница покрывает, почему это работает, что такое непрерывный батчинг и paged attention на самом деле, когда нужен настоящий движок обслуживания и как это размерить.

Почему последовательное обслуживание сжигает GPU

Вспомните формулу скорости: каждый декодированный токен читает практически все активные веса один раз (скорость). Обслуживая один поток, GPU делает всё это чтение ради одного токена одного пользователя. Теперь соберите восемь потоков в один прямой проход: веса читаются один раз и используются для восьми последовательностей — лишняя арифметика почти бесплатна, потому что декодирование ограничено пропускной способностью, а не вычислениями. Скорость на поток едва падает, а суммарная пропускная способность растёт почти линейно, пока не насытится пропускная способность или KV-память. Этот единственный факт — вся экономика локального обслуживания.

Статический против непрерывного батчинга

Наивная версия — статический батчинг — группирует запросы, пришедшие вместе, и гоняет батч, пока не закончит каждый участник. Работает, но плохо:

Статический батчинг Непрерывный батчинг
Формирование батча Один раз, когда группа соберётся Переоценивается на каждом шаге декодирования
Вход на лету Нет — ждёт следующего батча Да, слоты заполняются по мере прихода запросов
Короткий запрос в батче длинных Блокируется до конца самого длинного Завершается и сразу освобождает слот
Хвостовая задержка Плохая (блокировка головы очереди) Хорошая

Непрерывный (поитерационный) батчинг — дефолт в vLLM и SGLang — причина, почему эти движки держатся под реальным трафиком, пока наивные серверы рушатся.

Paged attention: лечение фрагментации KV

Каждый активный запрос нуждается в памяти KV-кэша (см. KV-кэш). Старый подход резервировал максимальный контекст каждого запроса авансом — так что чат на 2k токенов мог держать зарезервированный блок на 32k, запертый и непригодный для других. Большая часть пула KV простаивала. Paged attention хранит KV в блоках фиксированного размера, выделяемых по требованию, как ОС paging-ует память: отходы падают с большинства (авторы vLLM сообщали 60–80% в своей статье) до нескольких процентов, влезает в разы больше одновременных последовательностей, и пропускная способность следует. Та же идея, теперь стандарт в обслуживающих движках.

Цена для вас: ничего видимого пользователю — это изменение аллокатора; вы просто видите выше одновременную ёмкость на той же GPU.

Когда нужен настоящий движок обслуживания

Нагрузка Движок
Вы плюс хозяйство, несколько последовательных чатов Ollama / LM Studio — уже нормально
Несколько разработчиков неторопливо параллельно llama-server с параллельными слотами или параллельная среда Ollama
Продуктовый трафик, командный чат, реальные пользователи vLLM или SGLang
Флоты агентов с длинными общими системными промптами SGLang (кэш префиксов) или vLLM

Игровой угол этого форума — канонический пример последней строки: матчи шахмат и джанги гоняют несколько агентов, каждый запрашивает ход примерно раз в секунду — маленькие промпты, много потоков, общие системные промпты. Это ровно та нагрузка, которой нужен обслуживающий движок с батчингом, а не ollama run в цикле (см. агенты).

Пропускная способность против задержки

Каждая ручка меняет одно на другое: большие батчи поднимают суммарные tok/s, слегка опуская скорость на поток, а очередь поднимает TTFT под нагрузкой. Кодинг-ассистент для одного человека хочет параллелизм, ограниченный 1–2, чтобы поток человека никогда не стоял в очереди. Чат-сервис для тридцати человек хочет набитых батчей. Решите, кем вы являетесь, прежде чем тюнить (см. обслуживание насчёт TTFT против декодирования как отдельных измерений).

Ближайшее к бесплатному обеду — кэширование префиксов (SGLang): повторные длинные промпты превращаются в почти нулевой префилл, а это большинство агентных нагрузок.

Практичные ручки

# llama.cpp: параллельные слоты декодирования (контекст делится между слотами)
llama-server -m model.gguf -c 32768 -np 4

# Ollama: параллельные запросы на модель (перезапустите сервис после установки)
export OLLAMA_NUM_PARALLEL=4

# vLLM: две, которые важны
vllm serve model --max-num-seqs 32 --gpu-memory-utilization 0.90

Очереди образуются выше всех этих: когда каждый слот занят, новые запросы ждут. Следите за глубиной очереди и TTFT, а не за ощущениями.

Ставьте лимиты и выше по стеку: реверс-прокси с лимитом соединений падает быстро и честно, где глубокая очередь падает медленно и загадочно.

Планирование ёмкости, грубо

Что стоит запрос сверх весов — KV-кэш, на токен, на весь его контекст:

KV байт/токен ≈ 2 × слои × kv_heads × head_dim × bytes_per_value

Разбор, типичная плотная модель 8B (32 слоя, 8 KV-голов, размер головы 128, значения fp16):
2 × 32 × 8 × 128 × 2 B ≈ 131 KB на токен → разговор на 2k токенов ≈ 256 MiB KV → десять таких чатов ≈ 2.5 GB поверх ~5 GB весов.

(двойка — это K и V; см. KV-кэш). Агенты с длинным контекстом поэтому куда дороже на запрос, чем чат. Грубая таблица комфорта, с тяжёлыми оговорками — контексты чат-длины, только порядок величины:

GPU Модель Грубо одновременных лёгких чатов
8 GB 7–8B Q4 1–3
24 GB 8B Q4 ~10–30
24 GB 32B Q4 ~3–8
48 GB 70B Q4 ~5–15

Мерьте со своими реальными промптами: длина контекста двигает эти числа сильнее любой другой переменной.

Сигналы, что вы насыщены

  • TTFT растёт от миллисекунд к секундам по мере дня.
  • Глубина очереди устойчиво выше нуля; запросы ждут до первого токена.
  • tok/s на поток провисает по мере набивания батчей.
  • Логи vLLM показывают вытеснение или пересчёт KV — давление памяти, а не медлительность модели.

Любое из этого: ограничьте контекст, квантуйте KV-кэш или добавьте GPU — в этом порядке дешевизны — пока ваши пользователи не начали громко жаловаться.

Графируйте TTFT и глубину очереди через день — устойчивый рост означает нехватку ёмкости, пила означает всплески, которые можно поглотить очередью.

Аренда против покупки, эскиз

На момент написания арендованная GPU класса 24GB стоит примерно $0.50–2/час, а б/у карта 24GB — несколько сотен долларов; точка безубыточности где-то около 300–1,000 часов фактической генерации. Локальное побеждает по приватности, задержке и отсутствию лимитов (рамка в почему локально); аренда побеждает при взрывном спросе и моделях класса 80GB, которых не держит ни одна потребительская карта (см. математику VRAM насчёт того, что где влезает). Большинство людей переоценивает свои часы — инструментируйте реальную неделю, прежде чем решать.

Связанные разделы: скорость · KV-кэш · развёртывание эндпоинта · математика VRAM