Repository navigation
Persistence and Recovery.ru
Приёмочный критерий проекта: после перезапуска тот же разговор должен переиспользовать KV-блоки, восстановленные с NVMe — заметно быстрее, и с доказательством на уровне диска, а не только по скорости.
После каждого перезапуска с тем же промптом должны выполняться ВСЕ пункты:
-
usage.prompt_tokens_details.cached_tokens > 0в ответе (движок переиспользовал уже посчитанную работу prefill). - В
KVP_CACHE_ROOT/lmcache-server.logпосле перезапуска появляются строки события чтения L2/диска (строки по шаблонуretriev|loaded|restoreсL2|disk|secondary|file) — кэш реально отдаёт из своего хранилища, что подтверждается также физическими счётчиками чтения NVMe. - Байты L2 НЕ выросли, пересоздавая те же данные
(
bash scripts/budget-report.sh statusдо/после). - TTFT/prefill уменьшились относительно сопоставимой холодной базовой линии.
- Текст ответа корректен (визуальная проверка).
Одного ускорения для закрытия вехи НЕ достаточно.
Просмотренный протокол, механически реализованный в scripts/test-recovery.sh
(PASS/FAIL — машинный вердикт, код 0 только когда выполняются все проверки):
-
Маркеры позиции лога — до каждого запроса фиксируется смещение в байтах
в
lmcache-server.log; доказательствами для сценария считаются только события после этого маркера. Ничего из прошлых прогонов просочиться не может. - Запись до рестарта — прогревочный запрос должен ЗАПИСАТЬ блоки в хранилище L2 (байты каталога растут + события записи в логе). Если данных не записано, позднейшее «восстановление» ничего не доказывает — тест падает.
-
Различие L2 и L1 — после каждого рестарта тест требует события чтения ИМЕННО
с дискового уровня (а не любые строки «Retrieved», которые могут быть
попаданиями в RAM). Одного
cached_tokens > 0явно НЕДОСТАТОЧНО. - Жёсткий отказ готовности — если API не отозвалось за отведённое время после рестарта, тест немедленно падает; на мёртвом сервисе он не продолжает работу.
- Исключение альтернативных объяснений — переиспользование без событий дискового чтения после рестарта классифицируется как только RAM/prefix cache и помечается провалом.
-
Машинный вердикт —
PASS⇒ exit 0; любая неудачная проверка ⇒FAILс exit 1 иfailures.txtсо списком причин.
bash scripts/test-recovery.shСкрипт разогревает кэш длинным промптом, перезапускает контейнер vLLM и отправляет
идентичный запрос. Сводки по фазам — в benchmarks/results/<UTC-ts>-recovery/.
Ручной эквивалент:
# разогрев
bash scripts/benchmark.sh cold 3000
# перезапуск только vLLM, ожидание повторной готовности API
docker restart mimo-pro-tp4-kvp
until curl -fsS --max-time 3 -H "Authorization: Bearer $(head -n1 live/api_key | tr -d '[:space:]')" http://127.0.0.1:30007/v1/models >/dev/null 2>&1; do sleep 10; done
bash scripts/benchmark.sh after-vllm-restart 3000 # cached_tokens должен быть > 0test-recovery.sh продолжает: stop-cache.sh → start-cache.sh →
docker restart → тот же запрос. Здесь оба сервиса поднимаются с нуля:
восстановление доказывает ленивое пересоздание дискового индекса, задокументированное
для nixl_store_dynamic. Скорость восстановления/поиска фиксируйте из лога кэша.
| Наблюдение | Значение |
|---|---|
cached_tokens = 0 |
холодный (без переиспользования) |
cached_tokens > 0, БЕЗ событий чтения L2/диска |
тёплый — отдано из L1/RAM (сервис кэша выжил). Это ОЖИДАЕМЫЙ исход сценария A: запрос переиспользует KV, всё ещё находящийся в L1, поэтому с NVMe ничего читать не нужно. Это memory hit, а не отказ персистентности. |
cached_tokens > 0 И события чтения из L2 ПОСЛЕ ПОЛНОГО перезапуска (оба сервиса, L1 пуста) |
восстановлен с NVMe (именно это доказывает персистентность) |
Ожидания сценариев A и B (раунд 18): после перезапуска только vLLM сервис
кэша и его L1 живы, поэтому исправная система пишет
Prefetch request completed (L1+L2): N/N retained keys (N L1, 0 L2) — чистое
попадание в L1. Приёмочный скрипт НЕ должен падать на этом; только сценарий B
(полный перезапуск) требует доказательств L2 prefetch load completed /
(N L1, N L2).
Изменение любого поля идентичности — ревизия модели, токенизатор, KV-тип, геометрия блоков, TP, чат-шаблон — переводит деплой в НОВОЕ пространство: старые данные не адресуются. Это изоляция, не удаление. Откат изменения возвращает переиспользование старых данных.
scripts/test-recovery.sh создаёт свежий каталог результатов на каждый запуск;
ничего не перезаписывается. Итоговое число — медиана ≥3 повторов на конфигурацию
(см. страницу бенчмарков).