Двенадцать сборок

Локальный инференс на проброшенном GPU с OpenAI-совместимым эндпоинтом

Драйвер, рантайм и модель на G-L40S, обслуживаемые за TLS с API-ключом, и нагрузочный тест, который сообщает реальные токены в секунду, а не слайд вендора.

Что создаётся в итоге

Один GPU-инстанс, обслуживающий модель с открытыми весами через HTTP API, говорящий на совместимой с OpenAI схеме, так что все ваши клиентские библиотеки будут работать с ним, просто изменив базовый URL. За nginx, с TLS, API-ключом и systemd-юнитом, переживающим перезагрузки.

Написано на G-L40S: сорок восемь гигабайт видеопамяти на одной карте, проброшенной в инстанс через PCIe, а не разделяемой по времени между арендаторами. Это отличие — разница между предсказуемой задержкой и ожиданием чужой обучающей задачи. Карта ваша, пока вы её не отмените.

Перед началом

  • G-L40S с Debian 13. G-ADA на двадцать гигабайт подходит для меньших моделей; арифметика в шаге четыре подскажет, каких именно.
  • Два терабайта NVMe по этому плану — правильное место для весов. Скачивать сорок гигабайт дважды из-за того, что кэш был на корневой файловой системе, — раздражающий способ провести час.
  • Имя хоста, указывающее на инстанс, llm.example.com ниже.

1. Драйвер

sed -i "s/ main$/ main contrib non-free-firmware non-free/" /etc/apt/sources.list.d/debian.sources
apt update
apt install -y nvidia-driver firmware-misc-nonfree build-essential
reboot

После его возвращения:

nvidia-smi

Нужно, чтобы карта была в списке, версия драйвера напечатана, а использование памяти около нуля. Отсутствие карты на этом этапе почти всегда означает устаревший initramfs; update-initramfs -u и перезагрузитесь ещё раз, прежде чем открывать тикет.

nvidia-smi -q -d PERFORMANCE | grep -A3 "Clocks Event Reasons"
nvidia-smi -pm 1

Режим персистентности держит драйвер загруженным между процессами, убирая несколько секунд инициализации из каждого перезапуска.

2. Среда выполнения

apt install -y python3-venv python3-pip
install -d -o root -g root /srv/models /opt/vllm
python3 -m venv /opt/vllm/venv
/opt/vllm/venv/bin/pip install --upgrade pip
/opt/vllm/venv/bin/pip install vllm

Установка тянет большой набор колес, связанных с CUDA, и занимает время. Тем временем решите, какую модель использовать.

3. Выбор подходящего

Веса — это минимум, а не бюджет. Модель в шестнадцатибитной точности требует примерно два гигабайта VRAM на миллиард параметров, плюс кэш ключ-значение для каждого параллельного запроса, плюс около гигабайта на накладные расходы среды выполнения.

КартаВеса в 16-битРеальный размер моделиОстаток под кэш
L40S, 48 ГБ2 ГБ на миллиардДо примерно 20 миллиардов6–8 ГБ
L40S, 48 ГБ, 8-бит1 ГБ на миллиардДо примерно 34 миллиардов10 ГБ
RTX 4000 Ada, 20 ГБ2 ГБ на миллиардДо примерно 7 миллиардов5 ГБ
Две × L40S, 96 ГБ2 ГБ на миллиардДо примерно 40 миллиардов12 ГБ

Столбец кэша определяет, сколько человек могут одновременно пользоваться конечной точкой. Заполните карту весами до краёв — и вы построите очень быструю игрушку для одного пользователя.

4. Обслуживание

Укажите кэш на NVMe и запустите сервер. Подставьте идентификатор репозитория выбранной вами модели с открытыми весами; среда выполнения загрузит её при первом запуске.

cat > /etc/systemd/system/vllm.service <<EOF
[Unit]
Description=vLLM inference server
After=network-online.target

[Service]
Environment=HF_HOME=/srv/models
Environment=VLLM_API_KEY=<a long random string>
ExecStart=/opt/vllm/venv/bin/vllm serve <org>/<model> \\
  --host 127.0.0.1 --port 8000 \\
  --served-model-name local \\
  --max-model-len 16384 \\
  --gpu-memory-utilization 0.92 \\
  --max-num-seqs 32
Restart=on-failure
RestartSec=10
TimeoutStartSec=1800

[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload && systemctl enable --now vllm
journalctl -fu vllm

Привязка к loopback намеренная. Проверка API-ключа в среде выполнения — это общий секрет без ограничения скорости за ним, поэтому nginx отвечает за внешний доступ, а среда выполнения не касается публичного интерфейса.

Щедрый таймаут запуска существует потому, что первый запуск скачивает десятки гигабайт, а затем компилирует ядра. Последующие запуски занимают меньше минуты.

5. Прокси и TLS

server {
  listen 443 ssl;
  listen [::]:443 ssl;
  http2 on;
  server_name llm.example.com;

  ssl_certificate     /etc/letsencrypt/live/llm.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/llm.example.com/privkey.pem;

  location /v1/ {
    proxy_pass http://127.0.0.1:8000;
    proxy_buffering off;
    proxy_read_timeout 600s;
    proxy_set_header Host $host;
  }
}

proxy_buffering off — это строка, которая заставляет потоковые ответы действительно потоковыми. Оставьте её включённой, и токены будут приходить вежливыми порциями, когда nginx решит, что буфер полон, что выглядит в точности как медленная модель, но это не так.

Проверка

Начните с карты:

nvidia-smi --query-gpu=memory.used,memory.total,utilization.gpu --format=csv

Используемая память должна быть около девяноста процентов от общего объёма, потому что это то, что запросил --gpu-memory-utilization. Затем конечная точка:

curl -s https://llm.example.com/v1/models -H "Authorization: Bearer <the key>" | head -20

Одна модель, названная local. Теперь настоящее завершение, и замерьте время:

time curl -s https://llm.example.com/v1/chat/completions \
  -H "Authorization: Bearer <the key>" \
  -H "Content-Type: application/json" \
  -d '{"model":"local","messages":[{"role":"user","content":"List three prime numbers."}],"max_tokens":64}'

Наконец, измерьте её под нагрузкой, а не по одному запросу, — это единственная цифра, которую стоит приводить:

/opt/vllm/venv/bin/vllm bench serve \
  --backend openai-chat \
  --base-url https://llm.example.com \
  --endpoint /v1/chat/completions \
  --model local --num-prompts 200 --request-rate 8

Прочтите три числа из вывода: суммарную пропускную способность в токенах в секунду, медианное время до первого токена и 99-й процентиль полного времени. На одной L40S с моделью в диапазоне 10–20 миллиардов суммарная пропускная способность в сотни токенов в секунду и время до первого токена значительно меньше секунды — ожидаемая картина. Рост времени до первого токена с ростом параллелизма означает, что кэш ключ-значение слишком мал, поэтому уменьшите --max-model-len или --max-num-seqs и запустите снова.

После

Следите за температурой и троттлингом частоты первую неделю с помощью nvidia-smi dmon, поскольку карта, троттлящая по температуре при постоянной нагрузке, даёт именно ту перемежающуюся медлительность, которую обычно списывают на сеть. С точки зрения счетов помните, что GPU-инстанс стоит одинаково, занята карта или простаивает, поэтому лучше выполнять задачи пакетами, а не держать её прогретой. Цены — на странице GPU.

Готовы, когда вы готовы

Выберите город. Выберите размер. Оплатите монетой.

Никаких форм о том, кто вы, никакого ожидания одобрения человеком, никаких звонков для проверки. Счёт оплачен — и учётные данные приходят на почту.