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

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