Перейти к основному содержимому

For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://docs.nvidia.com/dynamo/llms.txt. For full content including API reference and SDK examples, see https://docs.nvidia.com/dynamo/llms-full.txt.

Использование HiCache

В этом руководстве описано, как запускать Hierarchical Cache (HiCache) SGLang с Dynamo и как KV router Dynamo интегрируется с HiCache для tier-aware выбора worker'ов, когда worker'ы разделяют внешний pool, такой как Mooncake.

Обзор

SGLang HiCache расширяет RadixAttention многоуровневым KV cache, который прозрачно перемещает pages между GPU HBM, host memory и необязательным external storage backend, например Mooncake. Полное описание самого HiCache — reference флагов, storage backends, memory layouts, prefetch policies — см. в документации SGLang:

Что Dynamo добавляет поверх HiCache:

  • Tier-aware routing. KV router отслеживает, на каком уровне cache находится каждый block (GPU / Host / External), и использует это при оценке candidate workers, а не только device overlap.
  • Shared-pool awareness. Когда настроен external backend вроде Mooncake, router запрашивает shared pool параллельно со своим indexer'ом, чтобы можно было снижать стоимость prefill для блоков, которые может получить любой worker, а не только блоков, которые есть локально у кандидата.

Если вы запускаете одного worker'а с HiCache и без shared pool, никакая конфигурация со стороны Dynamo не требуется — worker по-прежнему отправляет KV events в router как обычно.

Запуск SGLang с HiCache

Запустите worker с включенным HiCache:

python -m dynamo.sglang \
--model-path Qwen/Qwen3-0.6B \
--page-size 64 \
--enable-hierarchical-cache \
--hicache-ratio 2 \
--hicache-write-policy write_through \
--hicache-storage-backend nixl \
--skip-tokenizer-init

Затем запустите frontend:

python -m dynamo.frontend --http-port 8000

Флаги HiCache (--enable-hierarchical-cache, --hicache-ratio, --hicache-write-policy, --hicache-storage-backend, --hicache-mem-layout и т. д.) являются нативными для SGLang — Dynamo передает их без изменений. Полный reference флагов и рекомендации по настройке см. в документе SGLang's best-practices.

Tier-aware маршрутизация общего KV cache

Когда вы масштабируете систему до нескольких worker'ов SGLang, которые разделяют внешний pool, например Mooncake, router Dynamo можно сделать tier-aware. Он отслеживает размещение по уровням по событиям worker'ов и напрямую опрашивает shared pool, чтобы блоки, закэшированные где угодно в кластере, а не только на GPU candidate worker'а, учитывались при scoring worker'ов.

Зачем

По умолчанию radix tree router'а отражает только блоки, находящиеся в GPU HBM на каждом worker'е. HiCache незаметно понижает блоки до host memory и далее до Mooncake по мере заполнения device pool, но router не видит этих переходов. Worker, у которого полный prefix запроса находится на host + Mooncake, выглядит так же, как cold worker. В итоге router считает, что "можно получить из Mooncake за миллисекунды" и "нужно пересчитать с нуля" — это одно и то же.

Модель событий

HiRadixCache SGLang выдает события BlockStored / BlockRemoved, которые несут поле medium на каждом переходе между уровнями:

TransitionEvent emitted
Fresh prefill writes blocks to GPUstore(GPU)
GPU → Host copy (after async DMA completes)store(CPU_PINNED)
GPU evicted, block still resident on Hostremove(GPU)
Host evicted (block gone from all worker tiers)remove(CPU_PINNED)
Host → GPU promotion (load_back)store(GPU)
External → Host prefetch (L2 materialization)store(CPU_PINNED)

CPU_PINNED — это значение, которое HiRadixCache SGLang фактически выдает для блоков host-tier (page-locked memory). Далее в руководстве используется CPU_PINNED, чтобы совпадать с on-the-wire строкой; "Host" — это концептуальное имя уровня.

Несколько свойств, на которые опирается router:

  • Порядок. store(new_tier) отправляется до remove(old_tier), поэтому блок никогда не становится невидимым для router во время перехода.
  • Безопасность DMA. store(CPU_PINNED) для копии GPU→Host откладывается до тех пор, пока finish_event.synchronize() не подтвердит, что DMA завершилась — события никогда не срабатывают до того, как байты реально окажутся в памяти.
  • Отслеживание по уровням. Блок может одновременно находиться на GPU и Host. Router записывает оба состояния и выбирает уровень с наивысшим приоритетом при оценке overlap.

Как это работает

flowchart LR
Worker["SGLang Worker<br/>(HiRadixCache)"]
Mooncake["Mooncake<br/>shared pool"]
Router["Dynamo KV Router<br/>per-tier radix tree"]

Worker -- "KV events (store/remove + medium)" --> Router
Worker -- "writes pages" --> Mooncake
Router -- "batch_query on each request" --> Mooncake

Для каждого запроса router выполняет два lookup параллельно:

  • Its own radix tree, built from worker KV events (per-tier).
  • A batch query to the Mooncake master for blocks reachable from the shared pool.

Если запрос к shared pool не удается, router откатывается к scoring только по indexer'у и пишет warning. Запрос при этом все равно проходит.

Оценка

Для каждого candidate worker router вычисляет logit (меньше — лучше):

# Without shared cache
adjusted_prefill_blocks = max(
prefill_blocks
- overlap_score_credit * device_overlap_blocks
- host_cache_hit_weight * host_overlap_blocks
- disk_cache_hit_weight * disk_overlap_blocks,
0,
)
logit = prefill_load_scale * adjusted_prefill_blocks + decode_blocks

# With shared cache
shared_beyond = shared_cache_hits.hits_beyond(device_overlap_blocks)
adjusted_prefill_blocks = max(
prefill_blocks
- overlap_score_credit * device_overlap_blocks
- host_cache_hit_weight * host_overlap_blocks
- disk_cache_hit_weight * disk_overlap_blocks
- shared_cache_multiplier * shared_beyond,
0,
)
logit = prefill_load_scale * adjusted_prefill_blocks + decode_blocks

hits_beyond(n) считает страницы shared-cache на позициях >= n — "страницы за пределами моего device prefix, которые я все еще могу забрать из Mooncake вместо пересчета."

Разбор примера. Запрос состоит из 4 блоков, shared_cache_multiplier = 0.5, block_size = 1, overlap_score_credit = 1.0 (максимальный credit за device-local overlap). Shared pool содержит блоки 0–3.

WorkerDevice overlaphits_beyondDevice creditShared creditAdjusted prefillLogit
W02 (A, B)2 (C, D)2.01.01.01.0 — wins
W104 (A, B, C, D)0.02.02.02.0

W0 выигрывает, потому что сочетает device-local reuse с попаданиями в shared pool за пределами device prefix. Множитель задает соотношение стоимости fetch из Mooncake относительно нового GPU compute — 0.5 означает, что "получить из shared вдвое дешевле, чем пересчитать".

Требования

Tier-aware shared cache routing требует изменений в SGLang из sgl-project/sglang#22894 ("fix(hicache): emit KV events for L2 host cache insertions"). Этот PR еще не слит в main SGLang. Пока он не попадет в релиз SGLang, функция недоступна из обычного pip install sglang — нужно собирать SGLang из ветки PR (gh pr checkout 22894 && pip install -e python/ из репозитория SGLang). Этот раздел будет обновлен минимальной требуемой версией, когда #22894 выйдет в релизе.

Без PR #22894 события worker'ов несут только medium=GPU, и router не видит размещение на уровне Host — независимо от конфигурации Mooncake.

Также потребуется:

  • Запущенный Dynamo router с --shared-cache-type hicache (см. Configuration).
  • Доступный Mooncake master с хоста Dynamo frontend. Worker-side конфигурация Mooncake (master address, page size, TP/PP layout, split-head layout) публикуется автоматически через metadata регистрации каждого worker'а, если worker запущен с --hicache-storage-backend mooncake.

Настройка

Известное ограничение в 1.2.0. Если на worker'е SGLang одновременно заданы --enable-metrics и --disable-piecewise-cuda-graph, процесс может упасть при первой записи в KV-cache из-за гонки в upstream thread pool mooncake-transfer-engine. Ниже эти флаги не используются; сбор метрик по процессам через dynamo.frontend не затрагивается. Исправление на стороне mooncake отслеживается upstream.

SGLang worker — HiCache с Mooncake storage:

python -m dynamo.sglang \
--model-path Qwen/Qwen3-0.6B \
--page-size 64 \
--enable-hierarchical-cache \
--hicache-ratio 2 \
--hicache-write-policy write_through \
--hicache-storage-backend mooncake \
--hicache-storage-backend-extra-config '{"master_server_address": "mooncake-master.internal:50051"}' \
--skip-tokenizer-init

Запускайте дополнительные worker'ы на других GPU / хостах с той же конфигурацией Mooncake, чтобы они подключались к тому же cluster.

Dynamo frontend — включите tier-aware routing:

python -m dynamo.frontend \
--http-port 8000 \
--router-mode kv \
--shared-cache-type hicache \
--shared-cache-multiplier 0.5

Конфигурация

ФлагПеременная окруженияПо умолчаниюОписание
--shared-cache-typeDYN_SHARED_CACHE_TYPEnonenone отключает запросы к shared pool; hicache включает запросы к Mooncake.
--shared-cache-multiplierDYN_SHARED_CACHE_MULTIPLIER0.5Коэффициент скидки для попаданий из shared pool. 0.0 выполняет запросы, но игнорирует их; 0.5 считает shared hit вдвое дешевле device hit; 1.0 приравнивает shared и device hits.

Per-request overrides доступны через RouterConfigOverride.shared_cache_multiplier для A/B-экспериментов без перезапуска router'а.

Дополнительные флаги на worker'е не требуются. Когда задан --hicache-storage-backend mooncake, Dynamo публикует необходимые metadata (page size, TP/PP layout, master address) через blob ModelRuntimeConfig.engine_specific worker'а под ключом sglang_hicache_mooncake.

Проверка

События несут medium. Запустите worker с --log-level debug и проверьте лог:

python -m dynamo.sglang ... --log-level debug 2>&1 | grep -E 'BlockStored|BlockRemoved'
# BlockStored(block_hashes=[...], medium=CPU_PINNED)
# BlockRemoved(block_hashes=[...], medium=GPU)

Если medium отсутствует или всегда равен GPU, worker запущен на сборке SGLang без PR #22894.

Router видит shared pool. На Prometheus endpoint frontend'а доступны две новые histogram:

MetricMeaning
router_shared_cache_hit_rateFraction of request blocks found in the shared pool (0.0–1.0).
router_shared_cache_beyond_blocksBlocks in the shared pool beyond the selected worker's device overlap.
curl -s localhost:8000/metrics | grep shared_cache

Устранение неполадок

СимптомВероятная причинаИсправление
shared_cache_hit_rate is always 0Mooncake master недоступен с хоста router'аПроверьте сетевой путь; router пишет Shared cache query failed, когда не может достучаться до Mooncake.
События всегда несут только medium=GPUВ SGLang отсутствует PR #22894Пересоберите SGLang из ветки PR.
Worker'ы зарегистрированы, но router никогда не спрашивает shared cacheУ --shared-cache-type остался default noneУстановите --shared-cache-type hicache на frontend.
Запросы идут, но выбранный worker почти не меняется--shared-cache-multiplier 0.0Увеличьте multiplier — типичный стартовый диапазон 0.30.7.
Предупреждения о несовпадении page sizeУ router --page-size не совпадает с --page-size worker'аОни должны совпадать; router хэширует pages, используя page size worker'а.
Router пишет "no workers have HiCache enabled"Ни один worker не опубликовал metadata sglang_hicache_mooncakeУбедитесь, что worker'ы запущены с --hicache-storage-backend mooncake.

Дополнительные материалы