Якщо ваш LLM-сервіс зазнає високого навантаження при великій кількості одночасних користувачів, кожен запит обробляється послідовно — без батчингу throughput падає в рази, а latency зростає до неприйнятних значень. Ми налаштовуємо dynamic batching, щоб GPU працювала на 80%+ утилізації, а не на 5%. Наші інженери мають понад 4 роки досвіду в продакшені LLM та реалізували більше 20 проектів на vLLM, TensorRT-LLM та кастомних рішеннях. Dynamic batching об'єднує кілька паралельних запитів в один forward pass через GPU. Це ключовий механізм для високого throughput LLM: GPU паралельний і обробляє матричні множення ефективніше для великих батчів. Правильне налаштування батчингу дозволяє скоротити кількість необхідних GPU у 3-5 разів, що економить від $1.5k–5k на місяць на інфраструктурі. Наші гарантії: сертифіковані фахівці з досвідом у понад 20 проектах.
Чому батчинг критичний для LLM?
Без батчингу навіть потужна GPU A100 80GB видає лише 30 tokens/sec для моделі Llama-3-8B. При batch=16 – 300 tokens/sec, а при batch=64 – уже 900 tokens/sec. Таким чином, приріст у 30 разів — dynamic batching у 30 разів швидше за статичний. Однак latency p99 зростає з 200 мс до 400 мс, що все ще прийнятно для більшості real-time сценаріїв. Якщо у вас 100 concurrent користувачів, без батчингу кожен чекатиме своєї черги – загальний час відповіді може перевищити хвилину. З continuous batching всі запити обробляються паралельно, і час відповіді знижується до секунд.
| Розмір батча | Throughput (tokens/sec) | Latency p99 (ms) | GPU Utilization LLM |
|---|---|---|---|
| 1 | 30 | 200 | 15% |
| 16 | 300 | 250 | 65% |
| 64 | 900 | 400 | 90% |
Чому continuous batching виграє у статичного?
Static batching фіксує розмір батча і чекає його заповнення, що збільшує latency при низькому навантаженні. Continuous batching (in-flight batching) додає запити в батч динамічно — як тільки GPU звільняється, він одразу обробляє наступну пачку. Це знижує час очікування та підвищує utilisation. Continuous batching у 2–5 разів ефективніший за static batching за throughput.
| Тип батчингу | Розмір батча | Час очікування | Throughput | GPU Utilization |
|---|---|---|---|---|
| Static | Фіксований | Високий при низькому навантаженні | Середній | Низький |
| Dynamic | Адаптивний | Середній | Високий | Середній |
| Continuous | Адаптивний, in-flight | Низький | Дуже високий | Високий |
Continuous (In-flight) Batching у vLLM
Згідно з офіційною документацією vLLM, continuous batching реалізовано автоматично. Ключові параметри: max-num-seqs — максимальна кількість запитів у батчі, max-num-batched-tokens — загальна кількість токенів у батчі, scheduler-delay-factor — затримка перед формуванням батча. Приклад конфігурації:
python -m vllm.entrypoints.openai.api_server \ --model meta-llama/Llama-3-8b-instruct \ --max-num-seqs 256 \ --max-num-batched-tokens 32768 \ --scheduler-delay-factor 0.5 \ --use-v2-block-manager \ --enable-chunked-prefill Chunked prefill розбиває довгий prefill на чанки, що не блокує decode інших запитів:
--enable-chunked-prefill --max-num-batched-tokens 8192 Як налаштувати dynamic batching під конкретну GPU?
Виконайте ці кроки:
- Визначте модель та GPU. Наприклад, Llama-3-8B на A100-80GB.
- Виберіть фреймворк. vLLM — для швидкого старту, TensorRT-LLM — для максимальної продуктивності.
- Запустіть бенчмаркінг. Використовуйте навантажувальні тести з різною кількістю concurrent користувачів.
- Налаштуйте параметри.
max-num-seqs,max-num-batched-tokens,scheduler-delay-factor. - Моніторинг. Відстежуйте метрики
num_requests_running,avg_prompt_throughput_toks_per_s.
Які метрики моніторингу важливі для батчингу?
vLLM експортує метрики через Prometheus: num_requests_running (запити в активному батчі), num_requests_waiting (в черзі), avg_prompt_throughput_toks_per_s, avg_generation_throughput_toks_per_s. За допомогою цих метрик можна налаштувати баланс між throughput та latency. Для комплексного моніторингу використовуйте Grafana.
Типові помилки при налаштуванні батчингу:
- Занадто великий max-num-seqs: веде до зростання latency p99 через конкуренцію за пам'ять KV cache.
- Ігнорування chunked prefill: довгі промпти блокують decode, знижуючи utilisation.
- Відсутність бенчмаркінгу під реальне навантаження: параметри, підібрані на синтетичних даних, часто не працюють у продакшені.
Налаштування динамічного батчингу в TensorRT-LLM / Triton
# tensorrt_llm/config.pbtxt parameters { key: "max_tokens_in_paged_kv_cache" value: { string_value: "40000" } } parameters { key: "batch_scheduler_policy" value: { string_value: "guaranteed_no_evict" } } parameters { key: "executor_static_batch_size" value: { string_value: "-1" } } Ручна реалізація батчингу (приклад DynamicBatchInferenceServer)
Якщо використовується власний inference server:
import asyncio from dataclasses import dataclass from collections import deque import time @dataclass class PendingRequest: id: str prompt: str max_tokens: int future: asyncio.Future enqueued_at: float class DynamicBatchInferenceServer: def __init__( self, model, max_batch_size: int = 64, max_wait_ms: float = 20.0, max_tokens_per_batch: int = 16384 ): self.model = model self.max_batch_size = max_batch_size self.max_wait_ms = max_wait_ms self.max_tokens_per_batch = max_tokens_per_batch self.queue: deque[PendingRequest] = deque() self.lock = asyncio.Lock() self._batch_worker_task = None async def start(self): self._batch_worker_task = asyncio.create_task(self._batch_worker()) async def predict(self, prompt: str, max_tokens: int = 512) -> str: future = asyncio.get_event_loop().create_future() request = PendingRequest( id=str(time.time()), prompt=prompt, max_tokens=max_tokens, future=future, enqueued_at=time.time() ) async with self.lock: self.queue.append(request) return await future async def _batch_worker(self): while True: await asyncio.sleep(self.max_wait_ms / 1000) async with self.lock: if not self.queue: continue batch: list[PendingRequest] = [] total_tokens = 0 while (self.queue and len(batch) < self.max_batch_size and total_tokens + self.queue[0].max_tokens <= self.max_tokens_per_batch): req = self.queue.popleft() batch.append(req) total_tokens += len(req.prompt.split()) + req.max_tokens if not batch: continue prompts = [req.prompt for req in batch] max_tokens_list = [req.max_tokens for req in batch] try: outputs = self.model.generate_batch(prompts, max(max_tokens_list)) for req, output in zip(batch, outputs): if not req.future.done(): req.future.set_result(output) except Exception as e: for req in batch: if not req.future.done(): req.future.set_exception(e) Кейс: оптимізація для високонавантаженого чат-бота. Клієнт з навантаженням 2000 запитів на хвилину використовував 8 GPU A100 без батчингу. Після налаштування continuous batching з параметрами max-num-seqs=256 та chunked prefill вдалося обробляти те саме навантаження на 2 GPU. Економія інфраструктури склала $3.6k–5.2k на місяць. Окупність проекту — 3 тижні. Це доводить, що dynamic batching в 4 рази ефективніший за відсутність батчингу.
Завдяки налаштуванню dynamic batching наші клієнти скорочують витрати на GPU-інфраструктуру в 3-10 разів, досягаючи окупності проекту протягом 2-3 місяців. Економія становить від $1.4k–1.9k на місяць. Наш досвід та сертифікати гарантують якісний результат.
Що входить у налаштування
- Конфігурація inference server (vLLM, TensorRT-LLM або кастомний)
- Бенчмаркінг та підбір параметрів батчингу
- Інтеграція моніторингу метрик батчингу
- Документація з розгортання та підтримки
- Навчання команди (опціонально)
Орієнтовні терміни: від 2 до 10 робочих днів залежно від складності. Вартість розраховується індивідуально.
Отримайте консультацію з оптимізації throughput вашого LLM. Зв’яжіться — оцінимо проект за 1 день. Замовте аудит поточної конфігурації батчингу — ми виявимо вузькі місця та запропонуємо покращення з розрахунком економії.







