Налаштування балансування навантаження між GPU-інстансами

Налаштування балансування навантаження між GPU-інстансами

Напрямки AI-розробки

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1440
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1301
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    997
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1264
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    712
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    1002

Налаштування балансування навантаження між GPU-інстансами

Як відсутність балансування GPU вбиває latency LLM-сервісу

Уявіть: ви запустили чотири GPU-інстанси з vLLM, але 80% запитів йде на перший сервер. Інші простоюють, а користувачі скаржаться на таймаути. Причина — не налаштоване балансування навантаження. Для LLM це критично: один довгий запит на 4000 токенів може заблокувати сервер на хвилину, поки інші — idle. У результаті p99 latency злітає до 30 секунд, а утилізація GPU падає до 25%. Типовий кластер з 4 GPU без балансування втрачає до 50% пропускної здатності.

Грамотне балансування дозволяє скоротити витрати на GPU-інфраструктуру до 40% за рахунок рівномірної утилізації. Середня економія GPU-годин після впровадження — 30% за тієї ж навантаження. P99 latency знижується в 1.7 рази порівняно з Round Robin. Наприклад, для кластера з 4 GPU економія становить до $5000 на місяць. Якщо ви зіткнулися з подібними проблемами, зв'яжіться з нами — ми підберемо оптимальну конфігурацію під ваш сценарій.

Порівняння алгоритмів балансування для LLM

Алгоритм Принцип роботи Придатність для LLM Недоліки
Round Robin По черзі Низька Ігнорує завантаження: довгий запит перевантажує сервер
Least Connections Мінімум активних з'єднань Середня Не враховує довжину запитів (токенів)
Least Pending Tokens Мінімум токенів у черзі Висока Вимагає збору метрик з кожного бекенда
Custom (метрики GPU) За завантаженням VRAM/GPU Середня Залежить від моніторингу, складніше в реалізації

Документація vLLM: метрики для балансування

Least Pending Tokens — оптимальний вибір для сервісів з різнорідним навантаженням. Він використовує Prometheus-метрики vLLM (vllm:num_requests_waiting), щоби вибирати найменш завантажений інстанс. Наш досвід показує, що Least Pending Tokens кращий за Round Robin в 1.7 рази за p99 latency.

Приклад: Nginx з health checks і кастомний балансувальник

Нижче — базова конфігурація Nginx для upstream з чотирьох vLLM-серверів, з active health checks і таймаутами для streaming.

Конфігурація Nginx
upstream vllm_cluster { least_conn; server 10.0.1.10:8000 max_fails=3 fail_timeout=30s weight=1; server 10.0.1.11:8000 max_fails=3 fail_timeout=30s weight=1; server 10.0.1.12:8000 max_fails=3 fail_timeout=30s weight=1; server 10.0.1.13:8000 max_fails=3 fail_timeout=30s weight=1; keepalive 100; keepalive_requests 1000; keepalive_timeout 60s; } server { listen 443 ssl http2; server_name llm-api.internal; location /v1/ { proxy_pass http://vllm_cluster; proxy_http_version 1.1; proxy_set_header Connection ""; # Timeout для довгих streaming відповідей proxy_read_timeout 600s; proxy_send_timeout 600s; proxy_connect_timeout 5s; # Streaming: вимикаємо буферизацію proxy_buffering off; proxy_cache off; chunked_transfer_encoding on; # Circuit breaker proxy_next_upstream error timeout http_500 http_502 http_503; proxy_next_upstream_tries 2; proxy_next_upstream_timeout 10s; } location /health { proxy_pass http://vllm_cluster/health; } } 

Якщо потрібен більш інтелектуальний вибір бекенда — пишемо кастомний балансувальник на FastAPI, що опитує метрики в реальному часі.

from fastapi import FastAPI, Request import httpx import asyncio class LLMLeastPendingBalancer: def __init__(self, backends: list[str]): self.backends = {url: {"pending": 0, "healthy": True} for url in backends} self.client = httpx.AsyncClient(timeout=300) async def get_backend(self) -> str: """Вибираємо backend з найменшою кількістю pending токенів.""" healthy = {url: info for url, info in self.backends.items() if info["healthy"]} if not healthy: raise RuntimeError("No healthy backends") metrics = await self._fetch_metrics(list(healthy.keys())) best = min(metrics.items(), key=lambda x: x[1].get("vllm_num_requests_waiting", 0)) return best[0] async def _fetch_metrics(self, backends: list[str]) -> dict: tasks = [self._get_backend_queue(url) for url in backends] results = await asyncio.gather(*tasks, return_exceptions=True) return {url: result for url, result in zip(backends, results) if not isinstance(result, Exception)} async def _get_backend_queue(self, url: str) -> dict: response = await self.client.get(f"{url}/metrics") for line in response.text.split('\n'): if line.startswith('vllm:num_requests_waiting'): return {"vllm_num_requests_waiting": float(line.split()[-1])} return {"vllm_num_requests_waiting": 0} async def forward(self, request: Request) -> httpx.Response: backend = await self.get_backend() url = f"{backend}{request.url.path}" self.backends[backend]["pending"] += 1 try: return await self.client.request( method=request.method, url=url, content=await request.body(), headers=dict(request.headers) ) finally: self.backends[backend]["pending"] -= 1 app = FastAPI() balancer = LLMLeastPendingBalancer(["http://gpu1:8000", "http://gpu2:8000", "http://gpu3:8000"]) @app.api_route("/v1/{path:path}", methods=["GET", "POST"]) async def proxy(path: str, request: Request): return await balancer.forward(request) 

Чому sticky sessions критичні для LLM?

Якщо ваша LLM використовує KV-кеш prefix reuse (наприклад, загальний system prompt у чат-боті), без липких сесій кожен запит може потрапити на інший сервер — кеш марний. Рішення — consistent hashing за префіксом та sticky sessions.

def get_backend_by_prefix(prompt: str, backends: list[str]) -> str: prefix_hash = hashlib.md5(prompt[:256].encode()).hexdigest() idx = int(prefix_hash, 16) % len(backends) return backends[idx] 

Застосування sticky sessions збільшує cache hit ratio на 30-50%, скорочуючи latency на 20%. Без них типовий сервіс із загальним system prompt втрачає до 60% ефективності кешу.

Типові помилки при балансуванні GPU

  • Використання Round Robin для LLM — призводить до нерівномірного завантаження.
  • Відсутність health checks — трафік йде на впавший сервер.
  • Ігнорування streaming-таймаутів — клієнти отримують 502 помилки при довгих генераціях.
  • Неправильна конфігурація proxy_buffering — збільшує latency.
  • Відсутність failover GPU — при збої одного інстанса весь трафік втрачається.

Як налаштувати health checks для GPU-інстансів?

Метод Інструмент Складність Особливості
Пасивні (nginx) max_fails, fail_timeout Низька Не потребує додаткових налаштувань
Активні (nginx plus) health_check Висока Точно визначає стан, але платний
Кастомні HTTP /metrics Середня Працює тільки з vLLM та сумісними двигунами

Що входить у налаштування балансування під ключ

  1. Аналіз сценаріїв навантаження (кількість запитів, довжина токенів, вимоги до latency).
  2. Вибір алгоритму та стеку (Nginx, кастомний балансувальник, Envoy).
  3. Налаштування health checks, circuit breaker, таймаутів.
  4. Реалізація sticky sessions (якщо потрібен KV-кеш).
  5. Інтеграція з моніторингом (Prometheus + Grafana дашборди).
  6. Документація з експлуатації та Playbook для інцидентів.

Процес роботи

  • Аналітика — збір метрик поточної інфраструктури, профілювання запитів.
  • Проектування — архітектура балансування, вибір алгоритмів, схема failover.
  • Реалізація — розгортання конфігів або написання кастомного модуля.
  • Тестування — навантажувальне тестування з вимірами p50/p99/p999 latency.
  • Деплой — поетапний rollout з canary-релізом.

Строки та вартість

Базова настройка на Nginx — від 1 дня. Кастомний балансувальник з підтримкою Least Pending Tokens — від 3 до 5 днів. Вартість розраховується індивідуально, виходячи зі складності інфраструктури та вимог до відмовостійкості. Гарантуємо стабільність сервісу після впровадження — наші інженери з 5+ років досвіду в ML-інфраструктурі виконують роботу під ключ. Типовий ROI впровадження — 6 місяців.

Моніторинг розподілу навантаження

Після впровадження відстежуйте: розподіл RPS (має бути рівномірним ±20%), queue depth на кожному бекенді, error rate, latency p99. Налаштуйте алерт: «один бекенд приймає >80% трафіку» — сигнал про збій. При правильному налаштуванні p99 latency знижується до 5 секунд, а утилізація GPU підвищується до 95%. Cache hit ratio досягає 70% при використанні sticky sessions. Ми також навчаємо команду роботі з дашбордами.

Зв'яжіться з нами для попереднього аудиту — ми оцінимо поточну конфігурацію та запропонуємо оптимальне рішення. Замовте консультацію — допоможемо з вибором стратегії балансування для вашого GPU-кластера.