Repository navigation
Architecture.ru
Чат-клиент (OpenAI-совместимый, длинная история сообщений)
│ /v1/chat/completions
▼
vLLM (TP4 или другая параллельность, любая модель; production-рецепт не изменяется)
│ --kv-transfer-config: LMCacheMPConnector
│ (kv_connector_module_path фиксирует коннектор из LMCache)
▼
lmcache-сервер (отдельный процесс; ZMQ-порт запросов 5555, HTTP-админ 8080)
│ L1: буфер в RAM хоста (KVP_L1_SIZE_GB, по умолчанию 64 ГБ)
▼
Постоянный уровень L2: nixl_store_dynamic / POSIX → NVMe (KVP_CACHE_ROOT)
контроллер эвикции: LRU, trigger_watermark 0.9, eviction_ratio 0.1
- vLLM считает KV-чанки и сохраняет их через коннектор в L1 (RAM хоста).
- Контроллер записи асинхронно пишет каждый объект в L2 — по одному файлу на ключ чанка (временный файл + атомарный rename — сбой никогда не оставит «полуфайл»).
- При поиске сначала проверяется L1; промах уходит в L2 на диске. Дисковое попадание подтягивается в L1 и возвращается vLLM. Индекс в памяти стартует пустым и наполняется лениво из детерминированных имён файлов — это и обеспечивает восстановление после рестарта обоих сервисов.
- При выключении
persist_enabled=trueсохраняет файлы L2 (значение по умолчанию;falseудаляет их и ломает главное требование).
Именно семейство этого L2-адаптера LMCache документировано с семантикой
persist/recover: файлы открываются на каждую операцию (нет предварительно
выделенного реестра, умирающего с процессом, нет ограничения по числу дескрипторов
в масштабе 1.5 ТБ), а промах поиска уходит к детерминированному файлу на диске.
nixl_store (предварительно выделенный вариант) не документирует восстановление
после рестарта. POSIX-бэкенд выбран сознательно — самый простой надёжный путь к
NVMe — до всяких GDS.
Кэш-сервис — отдельный процесс. Рестарт vLLM не может стереть постоянные KV-данные; рестарт кэш-сервиса сохраняет их на диске. Режим, где кэш живёт только в памяти процесса, НЕ удовлетворяет требованию персистентности и не используется.
- id модели + ревизия модели (полный 40-символьный SHA коммита)
- имя и ревизия токенизатора
- эффективный KV-cache dtype (разрешённый —
autoне принимается) - геометрия KV: размер блока, число KV-голов, размер головы
- размер тензорного параллелизма (TP)
- имя коннектора + фиксированная идентичность сборки коннектора/vLLM
- максимальная длина модели
- digest чат-шаблона (sha256 отрендеренного шаблона)
Пространство — kvp-<первые 32 hex от sha256(канонического JSON полей)>.
Это логический идентификатор. На уровне хранилища LMCache он преобразуется в
model_name (CacheIdentity.lmcache_model_name()), и именно он разделяет файлы
на диске: адаптер nixl_store_dynamic именует файлы
<safe_model_name>_<kv_rank>_<group>_<chunkhash>.bin прямо в KVP_CACHE_ROOT
(плоская раскладка — каталогов kvp-<hash> НЕТ; префикс каждого имени файла —
санитизированное имя модели с этим пространством).
Любое пустое/неопределённое поле ⇒ промах кэша (пересчёт), никогда — неверное
попадание. Изменение любого поля переводит в НОВОЕ пространство; старые данные
становятся недостижимыми, но никогда не удаляются автоматически
(см. Хранилище и эвикция).
| Слой | Где | Модель-зависимый? |
|---|---|---|
| Идентичность / пространства | implementation/kvpersist/identity.py |
только входные данные |
| Бюджет и квоты | implementation/kvpersist/budget.py |
нет |
| Ранжирование удержания | implementation/kvpersist/retention.py |
нет |
| lmcache-сервер + L2-адаптер | configs/generic/* |
нет |
| Пины идентичности и геометрия | configs/<model>/identity.env |
да |
| Лаунчер vLLM | scripts/run-vllm-with-persist.sh |
да |
«Модельно-агностичный» означает, что механизм поддерживает несколько конфигураций — НЕ то, что их KV-данные взаимозаменяемы. Разные модели никогда не делят KV-блоки.
| Отказ | Поведение |
|---|---|
| промах / частичное попадание | пересчитывается только недостающая часть |
| несовместимая запись | недостижима по пространству ⇒ промах |
| битый / недописанный файл | поиск уходит мимо ⇒ пересчёт; вывод никогда не неверный |
| прерванная запись | атомарный rename ⇒ читатель видит старый или новый файл |
| прерванная эвикция | та же атомарность; отсутствие файла — обычный промах |
| диск полон / бюджет исчерпан | записи отклоняются; обслуживание продолжается без кэша |
| кэш-сервис недоступен | vLLM работает без кэша; корректность не меняется |
| падение любого процесса | рестарт ⇒ ленивое восстановление индекса с диска |
Сбой кэша никогда не может испортить вывод: худший случай — пересчёт.
-
lmcache-сервер— в фоне, pid-файлKVP_CACHE_ROOT/lmcache-server.pid. - Контейнер vLLM — имя
mimo-pro-tp4-kvp(лаунчер kv-persistence) или собственный контейнер рецепта при интеграцииKV_PERSIST=1. -
kvp-admin(консольная команда /python3 -m kvpersist.cli) — отчёты и явная очистка; никогда не запускается автоматически.