TensorRT-LLM and Dynamo on Spark Pairs
By the end of this lesson you will be able to describe how TensorRT-LLM runs across two DGX Sparks and how that differs from the Ray path, configure its parallelism through a YAML file rather than a pile of flags, name the container tags NVIDIA’s own pages disagree about and say what to do about it, explain what NVIDIA Dynamo is and what it needs, and say where each of the two belongs in a house rather than a data centre.
Part 8 taught trtllm-serve on one machine. This is the same software with MPI underneath it.
The two-Spark TensorRT-LLM path
Section titled “The two-Spark TensorRT-LLM path”The structural difference from Part 9’s Ray path is worth stating first, because it changes what you type and where you type it.
Two ways to make two machines behave as one
- vLLM with RayA long-lived cluster: start a head, join a worker, then run one vllm serve on the head. The cluster outlives the server, and you can restart the server without rebuilding the cluster.
- TensorRT-LLM with MPINo standing cluster. A container runs on each node; mpirun on the primary node launches one rank per node over SSH, and trtllm-llmapi-launch wraps trtllm-serve so it becomes the MPI job.
- What both need underneathThe same thing: matching usernames, passwordless SSH in both directions, addresses on the QSFP interfaces, and the interface names exported into the container.
NVIDIA’s playbook for the pair is a twelve-step procedure and the shape of it is this. Both nodes
get into the docker group. The primary node gets a plain-text hostfile listing both nodes’
QSFP addresses, one per line, which is what Open MPI reads to decide where ranks go. A container
starts on each node with host networking, the InfiniBand device mapped in, memory-lock limits
raised, the interface names exported, and an entrypoint script fetched from NVIDIA’s playbook
repository. The hostfile is then copied into the primary node’s container, a small YAML
configuration is written inside it, and the model is downloaded and served from that one container
with mpirun.
The container invocation carries the settings that make RDMA and MPI work, and they are worth recognising rather than copying blindly:
Fragment — not complete on its own
# The load-bearing arguments from NVIDIA's two-Spark TensorRT-LLM playbook.# Take the full command, and the current image tag, from the playbook itself.--network host # MPI and NCCL need the host's interfaces--device /dev/infiniband:/dev/infiniband--ulimit memlock=-1 # RDMA pins memory; an unlimited lock is required--ulimit stack=67108864-e UCX_NET_DEVICES="<your QSFP interfaces>"-e NCCL_SOCKET_IFNAME="<your QSFP interfaces>"-e OMPI_MCA_btl_tcp_if_include="<your QSFP interfaces>"-e OMPI_MCA_orte_default_hostfile="/etc/openmpi-hostfile"-e OMPI_MCA_rmaps_ppr_n_pernode="1" # exactly one rank per machineOMPI_MCA_rmaps_ppr_n_pernode set to one is the line that encodes “one GPU per Spark”. The serve
command then asks for a tensor parallel size of two, spanning the pair, exactly as the vLLM
playbook does and for the same reason: the cable is fast enough.
RunnableTrack S · DGX Spark
trtllm-serve nvidia/Qwen3-235B-A22B-FP4 \ --tp_size 2 \ --backend pytorch \ --max_num_tokens 32768 \ --max_batch_size 4 \ --extra_llm_api_options /tmp/extra-llm-api-config.yml \ --port 8355That command is launched under mpirun with trtllm-llmapi-launch in front of it, and the port
is one of the two the playbook’s prerequisites tell you to open: “network: open TCP ports 8355 (LLM)
and 8356 (VLM) on host for OpenAI-compatible serving.”
The model in that command is the interesting part. NVIDIA’s model support matrix for TensorRT-LLM on
Spark lists a couple of dozen checkpoints, mostly NVFP4 and FP8 conversions the vendor publishes
itself, and exactly one row is annotated “two Sparks only”: nvidia/Qwen3-235B-A22B-FP4. That
is NVIDIA naming a 235B-class mixture-of-experts model as the workload the pair exists for.
Qwen3-235B-A22B is Apache-2.0 licensed according to the model reference;
NVIDIA’s conversion is a separate repository whose own card you should check before relying on it,
and on 2026-09-09 that handle redirected to a repository named nvidia/Qwen3-235B-A22B-NVFP4. The
matrix also lists both gpt-oss models at MXFP4, which is the single-Spark comparison this part’s lab
uses.
Configuring parallelism in a file, not in flags
Section titled “Configuring parallelism in a file, not in flags”TensorRT-LLM’s parallelism documentation lists six strategies rather than Part 18’s five: tensor, pipeline, data, expert, context and “Wide Expert Parallel”, which it describes as “an advanced form of expert parallelism that addresses the inherent workload imbalance in large-scale MoE models through intelligent load balancing and expert replication”. The one-line summaries match Part 18’s definitions exactly, with tensor parallelism “best for: small batch sizes, memory-constrained scenarios” and pipeline parallelism “best for: large models that don’t fit in single GPU memory”.
Where it differs from vLLM is that the interesting choices live in a YAML file passed with
--extra_llm_api_options, not on the command line. For attention, the page gives
tensor_parallel_size alongside enable_attention_dp, which switches attention from a tensor split
to a data split. For mixture-of-experts layers it gives three patterns and one constraint:
| Pattern | What the file says | What it does |
|---|---|---|
| Tensor parallel experts | moe_tensor_parallel_size equal to tensor_parallel_size |
“Every expert’s weight matrix is sliced across all GPUs. Each GPU sees all tokens.” |
| Expert parallel | moe_expert_parallel_size equal to tensor_parallel_size |
“Full weights of each expert reside on a single GPU. Each GPU only sees tokens routed to its local experts.” |
| Hybrid | both set, multiplying to tensor_parallel_size |
“Each GPU stores a subset of experts (EP) and shards those weights further (TP)” |
The constraint is arithmetic and the documentation states it: “the product of
moe_tensor_parallel_size and moe_expert_parallel_size must equal tensor_parallel_size.” On a
two-Spark pair that leaves exactly two possibilities, which makes it a cheap experiment: run the
same load test under each and keep the file that wins.
The configuration file the playbook writes is short, and its contents are worth understanding
because two of the three keys are ones you already know from Part 9 under different names:
kv_cache_config with a free_gpu_memory_fraction of 0.9 is vLLM’s --gpu-memory-utilization,
cuda_graph_config with padding enabled is the graph capture that --enforce-eager disables, and
print_iter_log controls per-iteration logging.
Container tags, dated
Section titled “Container tags, dated”The architecture question from Part 5 applies here too. NVIDIA publishes the TensorRT-LLM images
multi-architecture, which is why the Spark can pull them at all, and the vLLM playbook’s own
troubleshooting table lists “container startup fails / missing ARM64 image” as a DGX Spark row.
Check what you pulled with docker image inspect before you spend an evening on a slow benchmark.
The playbook budgets “45-60 minutes for setup and API server deployment” and rates its own risk as medium because “container pulls and model downloads may fail due to network issues”. For a 235B-class NVFP4 checkpoint on a domestic connection, the download is the long pole and it is unattended.
Dynamo, and where it belongs
Section titled “Dynamo, and where it belongs”NVIDIA Dynamo is the third piece of this stack and the one this course surveys rather than teaches. Its documentation describes it as “a distributed inference runtime for generative AI systems that must operate at high throughput, low latency, and high reliability under changing traffic conditions”, and says it “is backend-agnostic (SGLang, TRT-LLM, vLLM, and others)”. It is not an engine. It is the thing that sits above one.
The architecture is three planes. The request plane has a frontend that “accepts and normalizes requests”, a router that “selects workers based on load and KV overlap”, and separate prefill and decode workers. The control plane has a planner that “computes scaling targets from live metrics” and a Kubernetes operator. The storage and events plane has KV events, a block manager that “manages block reuse, eviction, and offload/recall across memory tiers”, and NIXL, which “performs high-speed KV/data transfer across workers and memory domains”.
That last component is where the requirement bites. Dynamo’s RDMA page is unambiguous: “NVIDIA Dynamo uses RDMA to transfer KV cache between workers in disaggregated serving”, and “Dynamo needs RDMA for disaggregated serving, where prefill workers generate KV cache and hand it to decode workers.” It gives the alternative and its cost in the vendor’s own words: “the alternative is TCP over Ethernet, which is 200-500x slower for this transfer.” It also notes that aggregated deployments, where prefill and decode live in one worker, “transfer no KV cache between workers, and do not need RDMA.”
The other reason Dynamo is a survey here is that its centre of gravity is Kubernetes. The documentation has a Kubernetes user guide, an operator, custom resources, cloud-provider setup guides for three clouds, and a local command-line guide alongside them. The problems it solves are real problems: prefill and decode imbalance, KV recomputation, memory pressure across tiers, and dynamic demand. They are also problems that appear when traffic is bursty and machines are many, which is not the shape of a house.
Part 22 is where disaggregated serving is actually built, with vLLM’s own disaggregated prefill and SGLang’s prefill-decode split, on two machines and without an orchestrator. Read this section as the map: Dynamo is what the pattern looks like when it is productised, and knowing that helps when you read a benchmark that was measured on it.
When the playbook path beats vLLM
Section titled “When the playbook path beats vLLM”Both engines serve the same models across the same pair. Three things separate them in practice.
A tested combination. On aarch64, a playbook is NVIDIA saying “this image, this model, this command, on this machine”. Part 8 made this argument for one Spark and it is stronger for two, because the number of things that can be subtly wrong has roughly doubled.
Vendor checkpoints. TensorRT-LLM’s advantage is largely quantisation, and NVIDIA publishes
NVFP4 conversions of models it supports so you do not have to make one. The nvidia/ repository
prefix in the support matrix is the practical form of that advantage.
Configuration as a file. --extra_llm_api_options pointing at a YAML file is reproducible in a
way that a forty-token shell line is not, and it is the difference between a serving configuration
you can commit and one you retype.
Against that, vLLM’s Ray cluster is easier to inspect and easier to restart, its documentation covers the multi-node case in far more depth, and it is the engine the rest of this course uses. The honest recommendation is the one Part 8 gave: readers who want one engine for the whole course should stay with vLLM, and readers on Track S who want the vendor-validated path for a very large model should use the playbook and record which one they used.
Track S — NVIDIA DGX Spark
Both paths are yours. Start from the playbook you can reach: the TensorRT-LLM two-Spark page for the NVFP4 checkpoint NVIDIA marks “two Sparks only”, or the vLLM multi-node page from the previous lesson. Record the container tag, the model repository and the parallel configuration with every number.
Track X — AMD Ryzen AI Max+ 395Not supported
TensorRT-LLM and Dynamo both target NVIDIA GPUs; Dynamo's compatibility page lists only NVIDIA architectures.
The transferable idea is the configuration file. Part 19’s llama.cpp RPC cluster has no equivalent, and writing your own settings file that a script reads is a habit worth importing.
Track M — Apple siliconNot supported
TensorRT-LLM and Dynamo target NVIDIA GPUs; there is no macOS path for either.
Part 21 covers the Apple cluster. The comparison worth drawing is that Apple’s launcher,
mlx.launch, plays the role mpirun plays here, and it has the same property of leaving no
standing cluster behind.
Track N — NVIDIA desktop or laptopPartial
The software runs on x86 NVIDIA hardware, but the DGX Spark playbooks are written for GB10 and their container tags and model matrix are Spark-specific.
Everything above works on two x86 machines with the general TensorRT-LLM documentation instead of the playbook, and the parallelism configuration file is identical. What you lose is the tested combination, so expect to spend the time the playbook would have saved.
What this course validated, and what it did not
Section titled “What this course validated, and what it did not”Stated plainly, because Level 4 is where the gap between reading and running is widest.
Every page in this part was written from the documentation cited on it, read on 2026-09-09. Nothing in this part has yet been executed on hardware by the course. The validation pass will run the primary path on the reference cluster’s two Sparks and record versions, container tags and measurements per track, and the pending tables in the lab are where those numbers will land.
Specifically not validated: the TensorRT-LLM two-Spark path on any container tag; NVIDIA Dynamo on GB10 in any configuration; expert parallelism across two machines with the DeepEP backends; and any claim about which of the two serving paths is faster on the pair. Where this part states a number, it is either NVIDIA’s own specification figure, marked as such with its source, or arithmetic labelled as arithmetic.
Keep engine execution separate from service orchestration
Section titled “Keep engine execution separate from service orchestration”A specialised engine determines how the model executes. A serving framework can add routing, discovery, scheduling and separation of inference phases. Adding orchestration does not automatically fix an engine that cannot load the checkpoint or improve a single request whose bottleneck is local memory bandwidth.
Establish the smallest supported engine deployment first, with the exact image, model and configuration from the chosen playbook. Then add the pair and finally the orchestration features required by your workload. Save a baseline at each stage so the source of any latency or reliability change is visible.
List the extra services and ports introduced by orchestration, their persistent state and shutdown order. Test a worker restart and observe what happens to in-flight and subsequent requests. A production-style architecture is useful when it solves a measured scheduling or capacity problem; it also introduces components you must monitor and recover. Describe the supported stack you exercised and the workload that benefits rather than treating a complex launch as evidence of a better service.
TensorRT-LLM across two Sparks is an MPI job rather than a standing cluster: a container per node
with host networking and the InfiniBand device mapped in, a hostfile listing both QSFP addresses,
and mpirun with trtllm-llmapi-launch wrapping trtllm-serve at tensor parallel size two on
port 8355. Its parallelism lives in a YAML file passed with --extra_llm_api_options, where
moe_tensor_parallel_size times moe_expert_parallel_size must equal tensor_parallel_size, and
NVIDIA’s model matrix marks one NVFP4 checkpoint of a 235B-class mixture-of-experts model as
requiring two Sparks. Three NVIDIA pages named three different container tags on one day, so pin one
tag on both nodes and record it.
Dynamo is a distributed inference runtime above the engines, with a router, a planner, a KV block manager and NIXL for cache transfer, and it requires RDMA for disaggregated serving because the TCP alternative is, in NVIDIA’s own comparison, hundreds of times slower for that transfer. Its compatibility page names Blackwell and ARM64 Ubuntu without naming GB10, and this course treats it as surveyed rather than taught. Part 22 builds disaggregated serving on two machines without it.
Check your understanding
Sources for this lesson
8 verified · checked 2026-09-09
- 01DGX Spark playbook — TRT LLM for Inference§ Prerequisites; Model Support Matrix; Time and riskbuild.nvidia.com/spark/trt-llm2026-09-09
- 02DGX Spark playbook — TRT LLM for Inference, Run on two Sparksbuild.nvidia.com/spark/trt-llm/stacked-sparks2026-09-09
- 03TensorRT-LLM — Container Images§ Pre-built images on NGCnvidia.github.io/TensorRT-LLM/installation/containers.html2026-09-09
- 04TensorRT-LLM — Parallelism in TensorRT LLM§ Overview of parallelism strategies; attention module; FFN module; Wide-EPnvidia.github.io/TensorRT-LLM/features/parallel-strategy.html2026-09-09
- 05TensorRT-LLM — trtllm-serve CLI reference§ servenvidia.github.io/TensorRT-LLM/commands/trtllm-serve/trtllm-serve.html2026-09-09
- 06NVIDIA Dynamo — Overall Architecture§ Design goals; system model; request, control and storage planesdocs.nvidia.com/dynamo/knowledge-base/overview.md2026-09-09
- 07NVIDIA Dynamo — RDMA Setup§ What RDMA is; when you need itdocs.nvidia.com/dynamo/kubernetes/installation/rdma-setup/overview.md2026-09-09
- 08NVIDIA Dynamo — Compatibility§ Platform supportdocs.nvidia.com/dynamo/reference/compatibility.md2026-09-09
Every technical claim on this page was checked against the official documentation of the tool, vendor or model publisher on the date shown, at the version pinned for the course. Where the course disagrees with folklore, the source is how you can tell which one to trust.