vLLM кластер на 4 GPU

ТЕХНИЧЕСКОЕ ЗАДАНИЕ: vLLM кластер на 4 GPU

1. Цель задачи

Развернуть vLLM инференс‑сервер на четырёх GPU с включённым tensor parallelism (TP). Провести бенчмарк производительности (throughput, latency) на одном GPU (baseline) и на четырёх GPU с TP=4. Добиться ускорения минимум в 2 раза по throughput при одинаковых условиях (модель, batch size, длина запросов). Научиться конфигурировать multi‑GPU обслуживание больших языковых моделей в production‑стиле.

Ключевой результат vLLM-сервер, запущенный на 4 GPU, выдаёт ≥2× больше запросов в секунду (запросов/сек), чем тот же сервер на одном GPU, при сопоставимой latency (p95 не хуже baseline).

2. Исходные данные

Что нужноОткуда взять
Сервер с 4 GPU (NVIDIA)Физическая машина / облачный инстанс (AWS p4d.24xlarge, GCP a2-highgpu-4g, Azure NC96ads)
GPU драйверы (≥535), CUDA 12.xNVIDIA официальный сайт / apt / conda
Модель LLM (например, LLaMA-3-70B или Mistral-7B)Hugging Face, предварительный download
Python 3.10+ и PyTorch с CUDAconda / pip
vLLM (≥0.6.0)pip install vllm
Инструменты бенчмаркаvllm.entrypoints.openai.api_server --load-format, lm-eval, собственный скрипт
Мониторинг GPUnvidia-smi, nvtop, gpustat

Если нет реального сервера с 4 GPU — симулируем:

  1. Используем облачный инстанс с 4 GPU на 1–4 часа (стоимость ≈ 15–40 $)
  2. Если облака нет — можно взять машину с 2 GPU и запустить с --tensor-parallel-size 2, но метрики будут другими. Цель (2×) может быть достигнута и на 2GPU, если модель вмещается
  3. В крайнем случае — Docker контейнер с vllm и --num-gpus 4 на одной физической видеокарте (только для изучения параметров, без реального ускорения)

3. Технологический стек

КомпонентИнструментыНазначение
Язык и средаPython 3.10+, pip, conda, virtualenvЗапуск vLLM и бенчмарков
Инференс‑движокvLLM (vllm.entrypoints.openai.api_server)Развёртывание LLM, поддержка TP
FrameworksPyTorch 2.5+, CUDA 12.1+Базовые библиотеки для vLLM
Доп. утилитыhuggingface_hub, transformers, fastapi, uvicornЗагрузка модели, API сервер
Мониторинг GPUnvidia-smi, gpustat, nvtopЗагрузка, память, температура
Бенчмаркvllm.entrypoints.openai.run_batch, lm-eval, либо кастомный скрипт (aiohttp, asyncio)Измерение latency и throughput
ДокументацияMarkdown, JupyterАнализ результатов, отчёт

4. Этапы выполнения

Этап 1: Подготовка окружения (2 ч)

Действия

  1. Проверить доступные GPU

    nvidia-smi
    nvidia-smi topo -m   # topology (важно для TP)
    

    Убедиться: ≥4 GPU, драйвер ≥535, CUDA 12.x, связь GPU по NVLink/NVSwitch (если нет – TP будет медленнее).

  2. Установить зависимости

    conda create -n vllm python=3.10 -y
    conda activate vllm
    pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
    pip install vllm transformers huggingface_hub fastapi uvicorn aiohttp
    
  3. Скачать модель

    huggingface-cli download meta-llama/Meta-Llama-3-70B --local-dir ./models/Meta-Llama-3-70B
    

    Если модель не вмещается на один диск – использовать symbolic link или --cache-dir.

  4. Проверить, что vLLM стартует на 1 GPU (baseline)

    python -m vllm.entrypoints.openai.api_server \
        --model ./models/Meta-Llama-3-70B \
        --tensor-parallel-size 1 \
        --max-model-len 4096 \
        --gpu-memory-utilization 0.90 \
        --port 8000
    

    Убедиться, что сервер отвечает:

    curl http://localhost:8000/v1/models
    

Ожидаемый результат этапа

  • Рабочее окружение (conda, vLLM, модель)
  • Baseline‑сервер на одном GPU доступен по REST API

Этап 2: Бенчмарк baseline (1 GPU) — 3 ч

Действия

  1. Написать скрипт для стресс‑теста (или использовать встроенный vllm benchmark)
    Пример (bench_baseline.py):

    import asyncio
    import aiohttp
    import time
    import statistics
    
    API_URL = "http://localhost:8000/v1/completions"
    PROMPTS = ["Explain quantum computing in 3 sentences."] * 100   # 100 одинаковых запросов
    PAYLOAD = {
        "model": "./models/Meta-Llama-3-70B",
        "max_tokens": 128,
        "temperature": 0
    }
    
    async def send(session, prompt):
        payload = {**PAYLOAD, "prompt": prompt}
        async with session.post(API_URL, json=payload) as resp:
            return await resp.json()
    
    async def main():
        async with aiohttp.ClientSession() as session:
            start = time.monotonic()
            tasks = [send(session, p) for p in PROMPTS]
            results = await asyncio.gather(*tasks)
            total_time = time.monotonic() - start
        throughput = len(PROMPTS) / total_time
        latencies = [result["usage"]["total_tokens"] / ...]   # можно вычислять токены/сек
        print(f"Throughput: {throughput:.2f} req/s")
        # дополнительно: медиана, p95 latency
    asyncio.run(main())
    
  2. Запустить бенчмарк (не менее 3 прогонов)

    python bench_baseline.py
    

    Сохранить результаты в baseline_results.json.

  3. Измерить baseline метрики

Ожидаемый результат этапа
Файл baseline_results.json с точными задержками и throughput.


Этап 3: Разворот vLLM с Tensor Parallelism на 4 GPU (1 ч)

Действия

  1. Остановить сервер baseline (Ctrl+C)

  2. Запустить vLLM с TP=4

    CUDA_VISIBLE_DEVICES=0,1,2,3 python -m vllm.entrypoints.openai.api_server \
        --model ./models/Meta-Llama-3-70B \
        --tensor-parallel-size 4 \
        --max-model-len 4096 \
        --gpu-memory-utilization 0.90 \
        --port 8001
    
    • Параметр --tensor-parallel-size 4 распределяет слои модели по 4 GPU.
    • Убедиться, что все 4 GPU загружены (nvidia-smi показывает > 90% памяти).
    • Увеличить --gpu-memory-utilization до 0.95 если модель не помещается.
  3. Проверить, что сервер отвечает

    curl http://localhost:8001/v1/models
    

Ожидаемый результат этапа
Работающий vLLM сервер на 4 GPU с TP=4, отвечающий на запросы.


Этап 4: Бенчмарк TP=4 и сравнение с baseline (3 ч)

Действия

  1. Адаптировать скрипт бенчмарка

    • Изменить API_URL на http://localhost:8001
    • Если модель 70B, возможно потребуется уменьшить max_tokens или max_model_len из‑за памяти, чтобы избежать out‑of‑memory. Условия бенчмарка должны быть одинаковыми для baseline и TP.
  2. Запустить 3+ прогона

    python bench_tp4.py
    

    Сохранить в tp4_results.json.

  3. Вычислить ускорение

    speedup = throughput_tp4 / throughput_baseline
    print(f"Speedup: {speedup:.2f}x")
    

    Если ускорение <2× → перейти к этапу оптимизации (Этап 5).

  4. Собрать latency-распределение (p50, p95, p99) и загрузку GPU для обоих конфигураций.

Ожидаемый результат этапа
Таблица сравнения baseline vs TP4, расчёт ускорения, понимание узких мест.


Этап 5: Оптимизация для достижения ≥2× ускорения (3 ч)

Действия

  1. Анализ узких мест

    • Проверить inter‑GPU bandwidth (NVLink/NVSwitch vs PCIe).
    • Установить vllm с поддержкой --distributed-executor-backend ray (по умолчанию mp).
    • Использовать --pipeline-parallel-size 1 (не пересекается с TP для 4 GPU).
  2. Настройки повышения throughput

    • Batch size: увеличить max_num_seqs (например, 256 вместо 128).
    • Dtype: если модель позволяет – квантизация --dtype half или --quantization awq.
    • Scheduler: --use-v2-block-manager (если модель поддерживает PagedAttention v2).
    • Streaming: можно отключить или включить, в зависимости от задачи.
  3. Повторный замер
    После каждой оптимизации запускать бенчмарк и сохранять промежуточные результаты.
    Цель: throughput ≥ 2× baseline при acceptable latency (p95 не более 2× от baseline).

  4. Фиксация лучшей конфигурации
    Создать deploy_tp4.sh с оптимальным набором флагов.

Ожидаемый результат этапа
Достигнуто ≥2× ускорение; зафиксирован конфигурационный файл (config_tp4.json) и итоговый бенчмарк final_results.json.

5. Критерии приемки (Definition of Done)

  • Сервер vLLM успешно запустился на 4 GPU с --tensor-parallel-size 4
  • Проведён минимум 3 замера baseline (1 GPU) и 3 замера TP=4
  • Условия замеров идентичны: одна модель, одинаковые промпты, batch size, длина генерации
  • Ускорение по throughput >= 2.0× (отношение запросов/с TP4 к baseline)
  • p95 latency при TP4 не превышает p95 baseline (или оговорено иначе)
  • Конфигурация итогового запуска документирована (параметры, версии, команды)
  • Результаты сохранены в benchmark_report.md с таблицами и графиками (matplotlib/plotly)
  • Результаты воспроизводимы на другой машине (если есть специфика – указана)

6. Ожидаемый результат

Основной артефакт
benchmark_report.md – отчёт, содержащий:

  • Описание окружения (GPU, драйвер, версии ПО)
  • Команды запуска (baseline и TP4)
  • Таблица метрик:
КонфигурацияThroughput (req/s)p50 lat (s)p95 lat (s)GPU mem (GB avg)
1 GPUX.XY.YZ.ZW.W
4 GPU (TP=4)X.XY.YZ.ZW.W
  • График latency distribution (CDF)
  • Вывод: достигнуто / не достигнуто 2× ускорение, если нет – анализ причин

Дополнительно (опционально):

  • Скрипты bench_baseline.py, bench_tp4.py
  • Файл deploy_tp4.sh с оптимальным запуском
  • Логи nvidia-smi dmon (опция)

7. Возможные сложности и их решение

СложностьРешение
Модель не влезает в 4 GPUИспользовать квантизацию (AWQ/GPTQ) или модель с меньшим числом параметров (например, 13B вместо 70B). Проверить --gpu-memory-utilization 0.95.
Ускорение <2×Убедиться, что GPU соединены NVLink (а не PCIe). Уменьшить batch size или количество потоков. Проверить CPU‑GPU bottleneck.
vLLM выдаёт OOMУменьшить max-model-len, max-num-seqs, использовать --swap-space.
Запросы возвращают ошибкиПроверить формат промптов, версию модели, совместимость с эндпоинтом /v1/completions.
latency выше baselineВозможно, меж‑GPU коммуникация перевешивает выгоду от параллелизма. Попробовать увеличить max-num-seqs до 256–512.
Бенчмарк не воспроизводитсяЗафиксировать seed, temperature=0, одинаковое количество токенов. Использовать --load-format safetensors.

8. Бюджет времени (оценка)

ЭтапОписаниеВремя (ч)
1Подготовка окружения2
2Бенчмарк baseline (1 GPU)3
3Разворот TP=41
4Бенчмарк TP=4 и сравнение3
5Оптимизация до ≥2×3
Итого12

Примечание для первого раза может потребоваться +3–4 часа на отладку и понимание vLLM опций.

9. Связанные вопросы из базы знаний

ВопросТема
112vLLM и throughput (влияние batch)
203Distributed inference с TP
315Бенчмаркинг LLM (метрики, инструменты)
421CUDA multi‑GPU программирование
538Квантование AWQ для LLM
674Docker‑контейнеризация ML‑сервисов
789Мониторинг GPU (nvidia‑smi, gpustat)
810Масштабирование инференса LLM
891Tensor Parallel vs Pipeline Parallel

10. Чек-лист самопроверки

  • Я установил vLLM и проверил, что сервер запускается на одном GPU (curl работает)
  • Я замерил baseline не менее 3 раз и записал результаты
  • Я запустил vLLM с --tensor-parallel-size 4 и проверил, что все 4 GPU заняты
  • Я провёл идентичный бенчмарк на 4 GPU и подсчитал ускорение
  • Я добился ускорения ≥2× или задокументировал причины, по которым это не удалось
  • Я сохранил все конфигурации и результаты в финальный отчёт