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

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.

Кэширование моделей

Скачивание больших языковых моделей может занимать минуты. Без кэширования каждый pod загружает всю модель независимо, что расходует полосу пропускания и задерживает запуск. Dynamo поддерживает простой путь через общее хранилище и путь через ModelExpress для более быстрой доставки весов в крупных кластерах.

Вариант 1: PVC + Job для загрузки (рекомендуется)​

Самый простой подход: создайте общий PVC, один раз запустите Job для скачивания модели, затем примонтируйте PVC в ваш DynamoGraphDeployment.

Именно этот шаблон сегодня используют все рецепты Dynamo.

Шаг 1: создайте общий PVC​

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: model-cache
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 100Gi

Режим доступа ReadWriteMany нужен, чтобы несколько pod'ов могли одновременно монтировать PVC. Убедитесь, что ваш storage class поддерживает RWX (например, NFS, CephFS или общие файловые системы от облачного провайдера).

Шаг 2: скачайте модель​

apiVersion: batch/v1
kind: Job
metadata:
name: model-download
spec:
template:
spec:
restartPolicy: Never
containers:
- name: downloader
image: python:3.12-slim
command: ["sh", "-c"]
args:
- |
pip install huggingface_hub hf_transfer
HF_HUB_ENABLE_HF_TRANSFER=1 huggingface-cli download \
$MODEL_NAME --revision $MODEL_REVISION
env:
- name: MODEL_NAME
value: "Qwen/Qwen3-0.6B"
- name: MODEL_REVISION
value: "main"
- name: HF_HOME
value: /cache/huggingface
envFrom:
- secretRef:
name: hf-token-secret
volumeMounts:
- name: model-cache
mountPath: /cache/huggingface
volumes:
- name: model-cache
persistentVolumeClaim:
claimName: model-cache

Найдите путь к snapshot​

После завершения Job модель хранится в структуре кэша Hugging Face:

hub/models--<org>--<model>/snapshots/<commit-hash>/

Например, meta-llama/Llama-3.1-70B-Instruct превращается в:

hub/models--meta-llama--Llama-3.1-70B-Instruct/snapshots/9d3b8e0f71f8c1e0f9b7c2a3d4e5f6a7b8c9d0e1/

Чтобы найти точный commit hash после завершения Job загрузки:

kubectl run find-snapshot --rm -it --image=busybox --restart=Never \
--overrides='{
"spec": {
"volumes": [{"name": "c", "persistentVolumeClaim": {"claimName": "model-cache"}}],
"containers": [{
"name": "f", "image": "busybox",
"command": ["find", "/c/hub", "-mindepth", "3", "-maxdepth", "3", "-type", "d"],
"volumeMounts": [{"name": "c", "mountPath": "/c"}]
}]
}
}'

Либо посмотрите commit hash на странице модели в HuggingFace Hub в разделе Files and versions.

Этот путь нужен для поля pvcModelPath в спецификации DGDR (см. Model Deployment Guide — Model Caching).

Шаг 3: примонтируйте в DynamoGraphDeployment​

apiVersion: nvidia.com/v1alpha1
kind: DynamoGraphDeployment
metadata:
name: my-deployment
spec:
pvcs:
- create: false
name: model-cache
services:
VllmWorker:
volumeMounts:
- name: model-cache
mountPoint: /home/dynamo/.cache/huggingface

Все pod'ы VllmWorker, которые монтируют model-cache, теперь читают из общего кэша, а не скачивают модель отдельно для каждого pod'а. Если нужно, чтобы frontend тоже переиспользовал tokenizer и config-файлы, примонтируйте туда тот же PVC.

Кэш компиляции​

Для vLLM можно также кэшировать скомпилированные артефакты (CUDA graphs и т. п.) во втором PVC:

spec:
pvcs:
- create: false
name: model-cache
- create: false
name: compilation-cache
services:
VllmWorker:
volumeMounts:
- name: model-cache
mountPoint: /home/dynamo/.cache/huggingface
- name: compilation-cache
mountPoint: /home/dynamo/.cache/vllm

Вариант 2: ModelExpress (P2P distribution)​

ModelExpress - это сервис распределения весов модели, который интегрируется с pipeline загрузки весов vLLM. Он может публиковать веса модели с одного worker'а и позволять последующим worker'ам забирать эти тензоры из памяти GPU по NIXL/RDMA вместо повторной полной загрузки из хранилища.

ModelExpress также может использовать ModelStreamer как стратегию загрузки. ModelStreamer передаёт safetensors напрямую из object storage или локального пути файловой системы в память GPU через пакет runai-model-streamer. В такой схеме первый worker может стримить данные из хранилища, а затем публиковать метаданные ModelExpress, чтобы последующие worker'ы могли использовать P2P-путь.

Используйте этот путь, когда время запуска или время раскатки модели на весь флот важнее простоты общего PVC.

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

  1. Сервер ModelExpress работает в кластере и хранит метаданные о доступных источниках.
  2. Worker'ы vLLM используют загрузчик ModelExpress (--load-format mx в новых образах ModelExpress или mx-source / mx-target в старых split-loader-образах).
  3. Если совместимый источник уже обслуживает модель, новый worker забирает тензоры модели у этого источника по NIXL/RDMA.
  4. Если источник недоступен, worker откатывается к хранилищу. При общей файловой системе (RWX PVC, NFS, hostPath) worker читает напрямую из кэша сервера. Без общей файловой системы задайте MODEL_EXPRESS_NO_SHARED_STORAGE=1, чтобы клиент стримил файлы с сервера по gRPC; см. ниже Streaming Without Shared Storage. Когда задан MX_MODEL_URI, ModelStreamer может стримить safetensors из S3, GCS, Azure Blob Storage или локального пути.
  5. Kubernetes operator может внедрять MODEL_EXPRESS_URL во все pod'ы Dynamo на основе настройки платформы modelExpressURL.

Что настроить​

LayerWhat to configureNotes
Runtime imageВключите пакет Python modelexpress, а для ModelStreamer - runai-model-streamer и зависимости для object storage.Dynamo или vLLM выдаёт ошибку импорта, если worker использует формат загрузки ModelExpress, а пакет отсутствует.
Сервер ModelExpressРазверните сервер с Redis или backend метаданных на базе Kubernetes CRD.См. ModelExpress deployment guide.
Платформа DynamoЗадайте dynamo-operator.modelExpressURL.Оператор внедрит MODEL_EXPRESS_URL в pod'ы.
Worker vLLMЗадайте формат загрузки ModelExpress и укажите сервер.Новые образы ModelExpress используют --load-format mx; старые образы Dynamo могут использовать mx-source / mx-target.
ModelStreamerЗадайте MX_MODEL_URI для пути к хранилищу.Поддерживаются URI вида s3://..., gs://..., az://..., абсолютный локальный путь или ID модели Hugging Face, разрешаемый из локального кэша.

Настройка​

Установка с Dynamo Platform:

helm install dynamo-platform dynamo-platform-${RELEASE_VERSION}.tgz \
--namespace ${NAMESPACE} \
--set "dynamo-operator.modelExpressURL=http://model-express-server.model-express.svc.cluster.local:8080"

Настройка worker'ов на использование ModelExpress:

services:
VllmWorker:
extraPodSpec:
mainContainer:
image: <vllm-runtime-image-with-modelexpress>
command: ["python3", "-m", "dynamo.vllm"]
args:
- --model
- meta-llama/Llama-3.1-70B-Instruct
- --load-format
- mx
- --model-express-url
- http://model-express-server.model-express.svc.cluster.local:8080
env:
- name: VLLM_PLUGINS
value: modelexpress

Когда MODEL_EXPRESS_URL настроен в операторе, он автоматически внедряется как переменная окружения во все pod'ы компонентов. Передавать --model-express-url явно по-прежнему полезно в примерах, потому что worker проверяет наличие URL сервера при использовании старых форматов загрузки mx-source / mx-target.

Используйте формат загрузки, поддерживаемый вашим runtime image. В ModelExpress v0.3 и новее описан единый загрузчик mx. Некоторые образы Dynamo всё ещё используют старые раздельные имена загрузчиков mx-source и mx-target; им нужен тот же URL сервера, но отдельные роли source и target.

Стриминг без общего хранилища​

Если кэш сервера ModelExpress находится на неразделяемом томе (например, ReadWriteOnce PVC, развёртывание между namespace'ами или любая топология, где worker pod'ы не могут смонтировать ту же файловую систему, что и сервер), режим shared-storage по умолчанию ломается: сервер сообщает, что модель скачана, и возвращает свой локальный путь, worker не может прочитать этот путь изнутри своего pod'а, а загрузка незаметно откатывается к прямой загрузке из HuggingFace, сводя на нет смысл использования ModelExpress.

Задайте MODEL_EXPRESS_NO_SHARED_STORAGE=1 в каждом worker pod'е, чтобы переключить клиент ModelExpress в режим gRPC-стриминга. Тогда сервер будет отправлять файлы модели клиенту по существующему gRPC-каналу, а worker запишет их в свой локальный кэш.

services:
VllmWorker:
extraPodSpec:
mainContainer:
image: <vllm-runtime-image-with-modelexpress>
command: ["python3", "-m", "dynamo.vllm"]
args:
- --model
- meta-llama/Llama-3.1-70B-Instruct
- --load-format
- mx
env:
- name: VLLM_PLUGINS
value: modelexpress
- name: MODEL_EXPRESS_NO_SHARED_STORAGE
value: "1"

MODEL_EXPRESS_URL автоматически внедряется оператором (dynamo-operator.modelExpressURL); здесь задавать его явно не нужно. В этом режиме worker pod'ам не требуется volume mount для кэша ModelExpress.

Используйте этот путь, когда:

  • Сервер работает с RWO PVC или в namespace, отличном от worker'ов.
  • В кластере нет RDMA / InfiniBand fabric, поэтому P2P через NIXL невозможен.
  • Вы хотите, чтобы ModelExpress работал как централизованный сервер загрузки и кэширования (один pull из HuggingFace, затем рассылка по gRPC многим worker'ам) без развёртывания object storage и MX_MODEL_URI.

Режим с общей файловой системой всё равно быстрее, если он доступен, поэтому предпочитайте RWX PVC, смонтированный и на сервере, и на worker'ах, когда storage class это поддерживает. Полный разбор компромиссов и настроек (размер chunk'ов и т. п.) см. в ModelExpress storage access modes documentation.

ModelStreamer из object storage​

Задайте MX_MODEL_URI, когда первый worker должен стримить safetensors напрямую из хранилища, а не читать их из PVC или полагаться на предыдущий source-worker.

services:
VllmWorker:
extraPodSpec:
mainContainer:
image: <vllm-runtime-image-with-modelexpress-and-modelstreamer>
command: ["python3", "-m", "dynamo.vllm"]
args:
- --model
- meta-llama/Llama-3.1-70B-Instruct
- --load-format
- mx
- --model-express-url
- http://model-express-server.model-express.svc.cluster.local:8080
env:
- name: VLLM_PLUGINS
value: modelexpress
- name: MX_MODEL_URI
value: s3://my-model-bucket/meta-llama/Llama-3.1-70B-Instruct
- name: RUNAI_STREAMER_CONCURRENCY
value: "8"

ModelStreamer использует учётные данные базового cloud SDK:

Backend хранилищаПример MX_MODEL_URIВарианты учётных данных
S3 or S3-compatible storages3://bucket/path/to/modelIRSA / workload identity, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, AWS_DEFAULT_REGION и необязательный AWS_ENDPOINT_URL
Google Cloud Storagegs://bucket/path/to/modelGKE Workload Identity, Application Default Credentials или GOOGLE_APPLICATION_CREDENTIALS
Azure Blob Storageaz://container/path/to/modelManaged Identity, переменные окружения service principal или AZURE_ACCOUNT_NAME / AZURE_ACCOUNT_KEY
Local filesystem or PVC/models/meta-llama/Llama-3.1-70B-InstructПримонтируйте путь в worker pod

Учётные данные используются storage SDK в worker pod'е. Через сервер ModelExpress они не проходят.

Связь с Shadow Engine Failover​

ModelExpress и ModelStreamer - это пути загрузки и распределения модели. Они не требуются для Shadow Engine Failover, и их включение не создаёт standby engines.

Используйте Shadow Engine Failover только тогда, когда вам действительно нужна active/shadow topology восстановления на базе GPU Memory Service (GMS), DRA и backend load format вроде --load-format gms. Держите конфигурацию ModelExpress / ModelStreamer отдельно, если только вы не проверили комбинированный workflow для вашего runtime image и кластера.

Когда использовать ModelExpress​

ScenarioRecommended Approach
Малый кластер, простая настройкаPVC + Job для загрузки
Большой кластер, много узловModelExpress P2P
Модели уже лежат в общем хранилище (NFS)PVC
Модели в S3, GCS, Azure Blob Storage или локальных safetensors-путяхModelExpress + ModelStreamer
Частые обновления модели по всему флотуModelExpress P2P, при необходимости дополненный ModelStreamer
Сервер ModelExpress с неразделяемым хранилищем (RWO PVC, cross-namespace)ModelExpress с MODEL_EXPRESS_NO_SHARED_STORAGE=1

See Also​