# vLLM KV Offloading: кеш префикса в RAM и проверка задержки

Источник: https://modelium.tech/zhurnal/vllm-kv-offloading/

KV Offloading в vLLM расширяет кеш повторяемых префиксов: завершённые KV-блоки выгружаются с GPU в память хоста и при необходимости возвращаются. Для первого теста используйте CPU-tier OffloadingConnector на совместимом GPU, затем сравните повторный запрос с контролем без выгрузки. Сам факт ответа или падение свободной RAM не доказывает полезный hit: проверяйте счётчики загрузки и время до первого токена на одинаковой нагрузке.

**Проверено по документации 5 октября 2026 года:** vLLM Git `f98d1fc` и карточка Qwen3-0.6B HF `c1899de`. Это схема эксперимента читателя, не результат собственного запуска Modelium [s1](#src-s1)[s8](#src-s8).

## Когда выгрузка KV-блоков полезнее обычного кеша?

KV-кеш хранит вычисленное состояние токенов. Если несколько запросов используют одинаковое начало, prefix caching позволяет переиспользовать блоки вместо нового вычисления; ключи блоков зависят от префикса и условий кеширования. Подробности обычного GPU-кеша и изоляции — в [гайде по prefix caching](/zhurnal/vllm-prefix-caching/) [s4](#src-s4). OffloadingConnector добавляет более вместительный CPU-tier: завершённые блоки копируются с GPU в закреплённую память хоста, а при обращении загружаются обратно. Это полезно для *проверяемой гипотезы* о повторном использовании длинного общего начала, когда GPU-кеш вытесняется нагрузкой; серверная стоимость CPU RAM и пересылки может свести выигрыш на нет [s1](#src-s1).

Это **не** выгрузка весов модели в RAM и не [Sleep Mode](/zhurnal/vllm-sleep-mode/), который ставит на паузу обслуживание и иначе обращается с KV. Это также не [FP8-квантование KV-кеша](/zhurnal/vllm-kv-cache-fp8/): квантование меняет представление элементов кеша, а коннектор добавляет уровень хранения. Если повторные запросы полностью помещаются в GPU-кеш, CPU-tier может не дать выигрыша; без сравнения на ваших запросах утверждать обратное нельзя [s1](#src-s1)[s4](#src-s4).

## Какой сервер, модель и объём RAM выбрать для теста?

Маршрут выбора: **задача с повторяющимся длинным префиксом → конкретная модель → совместимый GPU и свободная RAM → vLLM с коннектором → подтверждённый возврат блока и измерение TTFT**. Документация этого коннектора перечисляет CUDA, ROCm и XPU; это перечень backend, а не обещание совместимости конкретного ускорителя и драйвера. В качестве небольшого идентифицируемого примера можно взять `Qwen/Qwen3-0.6B`: репозиторий существует, но теста именно этого стека на вашем оборудовании здесь нет. Сначала подготовьте обычный сервер по [гайду vLLM](/zhurnal/vllm/) и проверьте модель без коннектора [s1](#src-s1)[s8](#src-s8).

Для первого CPU-only tier выберите **свободный бюджет памяти хоста**, который не вытеснит ОС, веса и другие процессы. Параметр `cpu_bytes_to_use` измеряется **байтами суммарно для всех workers**, не на каждый worker. Пример официальной документации использует `1000000000` байт и `block_size: 64`; это пример конфигурации, не минимальная RAM и не гарантия роста hit-rate. Для CPU-only схемы авторы рекомендуют размер tier больше общего GPU KV cache: иначе немедленно выгружаемые блоки лишь повторяют хранящееся на GPU. Нельзя вывести подходящий бюджет RAM из размера файла весов модели или одного снимка свободной VRAM [s1](#src-s1).

**Не смешивайте два интерфейса.** В коде vLLM есть `kv_offloading_size` (GiB) и `kv_offloading_backend` (`native` или `lmcache`) в `CacheConfig`. Здесь разбирается документированная конфигурация *OffloadingConnector* через `--kv-transfer-config` и его `cpu_bytes_to_use` в байтах. Не устанавливайте оба набора флагов «на всякий случай» и не считайте разные единицы одним и тем же бюджетом; сравнивайте по отдельности только после проверки версии и режима. Данные о поведении одного интерфейса не доказывают поведение другого [s1](#src-s1)[s2](#src-s2).

## Как включить CPU-tier и получить контрольный ответ?

Запускайте на закрытом тестовом хосте с доступом к выбранной модели и совместимым backend. Сначала без KV-коннектора сохраните `vllm --version`, настройки, `/v1/models`, `/health` и ответ `/v1/completions` для одинакового длинного префикса. Для старта с коннектором команда по закреплённой документации, в одну строку: `vllm serve Qwen/Qwen3-0.6B --host 127.0.0.1 --port 8000 --kv-transfer-config '{"kv_connector":"OffloadingConnector","kv_role":"kv_both","kv_connector_extra_config":{"block_size":64,"cpu_bytes_to_use":1000000000}}'`. Сначала остановите контрольный экземпляр, чтобы не столкнуться на порту и не сравнивать две конкурирующие нагрузки на одном GPU. `127.0.0.1` — редакционная граница теста; она не делает сервис безопасным для недоверенного локального процесса и не заменяет сетевую политику [s1](#src-s1)[s6](#src-s6)[s7](#src-s7)[s8](#src-s8).

Убедитесь, что сервер поднялся, `GET http://127.0.0.1:8000/health` отвечает, а `/v1/models` показывает ожидаемое имя. Используйте **один и тот же длинный префикс** в запросах `/v1/completions`, одинаковые параметры генерации и явный `model` из ответа сервера. Повторите запрос, затем создайте контролируемое давление другими тестовыми префиксами так, чтобы первоначальные GPU-блоки могли вытесняться; не делайте этого на рабочем сервисе. Второй вызов первоначального префикса сравнивайте с контрольным сервером без коннектора при той же модели, длинах, параллелизме и нагрузке. Просто повторить короткий запрос недостаточно: ответ мог прийти из GPU-кеша, и CPU-tier не участвовал [s1](#src-s1)[s4](#src-s4)[s7](#src-s7).

В документации предусмотрены и тонкие настройки: `max_load_tokens` в `kv_transfer_params` ограничивает число токенов загрузки из внешнего tier **сверх** уже доступных на GPU; `0` отключает внешнюю загрузку только для конкретного запроса, оставляя GPU-кеш. `max_offload_tokens` отдельно ограничивает сохранение блоков запроса в tier. Оба параметра отмечены авторами как экспериментальные; для первого сравнения оставьте их неуказанными. Значение `offload_prompt_only` по умолчанию `true`: коннектор ориентирован на префиксную часть, не на «ускорение любого декодирования» [s1](#src-s1).

## Как доказать hit и оценить задержку, а не только получить HTTP 200?

Перед серией и после неё снимите `/metrics`. Исходник OffloadingConnector определяет семейства `vllm:kv_offload_store_bytes` и `vllm:kv_offload_load_bytes` для переноса; ищите в экспорте прирост счётчика **загрузки** при возврате к вытесненному префиксу, а не только записи при первом запросе. Счётчик переноса сам по себе не доказывает, что ответ точен, а отсутствие прироста при быстром повторе может означать hit на GPU. Одновременно проверьте содержимое ответа, статус модели и изменения host RAM/VRAM на своём стенде. У сервера `/metrics` документирован отдельно от `/health`, поэтому один успешный health не подменяет эту проверку [s3](#src-s3)[s5](#src-s5)[s7](#src-s7).

Для задержки измерьте время до первого токена (TTFT) на серии **одинаковых** запросов в двух режимах и сохраните условия замера: ревизия vLLM, модель, GPU, CPU/RAM, префикс, длины, параметры sampling, соседняя нагрузка и число повторов. Документация vLLM описывает гистограмму `vllm:time_to_first_token_seconds`; агрегированные бакеты полезны для распределения, но для точного сопоставления двух отдельных ответов дополнительно фиксируйте время на клиенте. Редакционная формула разницы: `ΔTTFT = TTFT(повтор с OffloadingConnector) − TTFT(сопоставимый повтор без него)`; положительное значение означает большую задержку именно в этих условиях, отрицательное — меньшую. Ни наличие CPU-tier, ни авторское слово «асинхронно» не обещает ускорения вашего сценария [s1](#src-s1)[s5](#src-s5).

Если есть разные группы пользователей, учитывайте `cache_salt`: документация vLLM использует его для ограничения переиспользования блоков между группами. Для честного теста одинаковый соль/контекст должны использовать только запросы одной доверенной группы; изменение соли может разрушить hit и изоляцию не следует снимать ради красивых чисел. API-key vLLM защищает только документированные префиксы путей, не все маршруты; не выставляйте тестовый сервер наружу и не принимайте ключ за полную границу безопасности [s4](#src-s4)[s6](#src-s6).

## Что исправить, если повтор медленный или возврата нет?

- **Счётчик **`**store**`** растёт, **`**load**`** нет.** Проверьте идентичность начального префикса, модель и соль. Если повтор ещё в GPU-кеше, внешний tier не нужен; если первоначальный блок не поместился в CPU-tier, пересмотрите бюджет с сохранением запаса RAM. `cpu_bytes_to_use` суммарный, а для single-tier авторы рекомендуют превышать совокупный GPU KV-кеш [s1](#src-s1)[s3](#src-s3)[s4](#src-s4).

- **RAM занята, а TTFT хуже.** Выгрузка добавляет копирование/поиск блоков, и собственная нагрузка может не выигрывать. Повторите тест с контрольным режимом и одинаковой конкуренцией, а затем уменьшите или отключите tier. Не утверждайте эффективность по одному ответу или по времени прогрева модели [s1](#src-s1)[s5](#src-s5).

- **Сервер не стартует.** Сверьте точное имя `OffloadingConnector`, JSON в `--kv-transfer-config`, `kv_role: kv_both`, поддерживаемый backend, свободную RAM и согласованность `block_size` с GPU block size. В документации `block_size` должен быть кратен размеру GPU-блока; при иных конфигурациях уместен альтернативный `blocks_per_chunk` [s1](#src-s1).

- **Нужна только экономия GPU-памяти кеша.** Это не доказательство, что модель целиком помещается на GPU или что размер весов равен нужной RAM. Если цель — сократить формат KV, проверьте [FP8-гайд](/zhurnal/vllm-kv-cache-fp8/); если цель — временно освободить память при остановке инференса, изучите [Sleep Mode](/zhurnal/vllm-sleep-mode/) [s1](#src-s1)[s2](#src-s2).

## Как завершить проверку и выбрать следующий шаг?

Сохраните контрольный ответ, снимок метрик и условия обоих прогонов. Если есть подтверждённая загрузка блоков из CPU и приемлемые TTFT/RAM на вашей рабочей смеси запросов, закрепите версию, модель и бюджет RAM в собственной конфигурации; если прироста нет, оставьте обычный GPU-кеш. Следующий шаг — [подготовить и проверить повторный префикс](/zhurnal/vllm-prefix-caching/), а для серверных метрик — [гайд vLLM Prometheus](/zhurnal/vllm-metrics-prometheus/). Здесь описана проверка по первоисточникам; собственный запуск и измерения Modelium не выполнял [s1](#src-s1)[s3](#src-s3)[s4](#src-s4)[s5](#src-s5).

## Источники

1. [vLLM KV Offloading Usage Guide: CPU-tier и настройка](https://github.com/vllm-project/vllm/blob/f98d1fc49361cb50457f6109c3c01a5c77e415b4/docs/features/kv_offloading_usage.md) — получено 2026-10-05
2. [vLLM CacheConfig: нативный параметр KV offloading](https://github.com/vllm-project/vllm/blob/f98d1fc49361cb50457f6109c3c01a5c77e415b4/vllm/config/cache.py) — получено 2026-10-05
3. [vLLM OffloadingConnector: имена счётчиков переноса](https://github.com/vllm-project/vllm/blob/f98d1fc49361cb50457f6109c3c01a5c77e415b4/vllm/distributed/kv_transfer/kv_connector/v1/offloading/metrics.py) — получено 2026-10-05
4. [vLLM Prefix Caching: повторное использование и cache_salt](https://github.com/vllm-project/vllm/blob/f98d1fc49361cb50457f6109c3c01a5c77e415b4/docs/design/prefix_caching.md) — получено 2026-10-05
5. [vLLM Production Metrics: TTFT и /metrics](https://github.com/vllm-project/vllm/blob/f98d1fc49361cb50457f6109c3c01a5c77e415b4/docs/usage/metrics.md) — получено 2026-10-05
6. [vLLM Security: границы API key и открытые маршруты](https://github.com/vllm-project/vllm/blob/f98d1fc49361cb50457f6109c3c01a5c77e415b4/docs/usage/security.md) — получено 2026-10-05
7. [vLLM Online Serving: список моделей, health, completions, metrics](https://github.com/vllm-project/vllm/blob/f98d1fc49361cb50457f6109c3c01a5c77e415b4/docs/serving/online_serving/README.md) — получено 2026-10-05
8. [Qwen/Qwen3-0.6B: карточка конкретной модели](https://huggingface.co/Qwen/Qwen3-0.6B/blob/c1899de289a04d12100db370d81485cdf75e47ca/README.md) — получено 2026-10-05
