
我先從一個很現(xiàn)實的問題說起手頭有 8 張 H100線上大模型的并發(fā)推理性能就是上不去GPU 利用率忽高忽低單卡顯存動不動就爆。這已經(jīng)不是“模型訓練完就能上線”的時代了。推理側正在變成真正的戰(zhàn)場而 NVIDIA Dynamo 這個分布式 AI 推理中間層恰好就是沖著這個痛點來的。它的目標很直接讓分布在大規(guī)模 GPU 集群上的推理服務像一臺邏輯上的“超大號 GPU”那樣被調度、被管理把分布式推理的效率往上拉一大截。這篇文章不打算做成官方文檔的復讀機而是從一個實際做推理系統(tǒng)的人的角度聊聊 Dynamo 到底解決了什么問題、核心機制有哪些、以及如果你想上手應該從哪些地方切入。1. 項目概述NVIDIA Dynamo 到底是個什么角色1.1 先理解“推理系統(tǒng)”和“訓練系統(tǒng)”為什么不一樣很多人對分布式系統(tǒng)的第一印象來自大模型訓練比如 Megatron、DeepSpeed、FSDP 這些框架。訓練的特點是任務確定、并行策略明確、可以花很長時間做流水線調度和梯度同步。但推理完全不同。用戶的請求是實時到達的每個請求的輸入輸出長度不一樣有的問一句“你好”有的直接丟一篇幾萬字的長文進來算力消耗相差幾十倍。又因為大模型是自回歸生成每個 token 的生成都依賴于前面的 token這種串行依賴讓推理對延遲的要求非常苛刻。更重要的是顯存。推理時的 KV Cache 會隨著并發(fā)請求數(shù)量和序列長度動態(tài)增長同一個 batch 里不同請求的長度差異會造成嚴重的顯存碎片和算力浪費。你如果只拿訓練時的“數(shù)據(jù)并行 / 張量并行”思維去做推理很快就會遇到一個尷尬局面卡多了以后通信開銷甚至蓋過了算力收益。所以分布式 AI 推理不是一個“把模型切幾塊”的問題而是一個“如何動態(tài)管理海量請求、KV Cache 和異構算力”的調度問題。1.2 NVIDIA Dynamo 的定位推理時代的“分布式操作系統(tǒng)”NVIDIA Dynamo 不是又一個推理引擎它不負責具體的算子執(zhí)行也不直接實現(xiàn) Transformer 的前向計算。它的定位更像是一個分布式推理的編排與控制平面。類比一下TensorRT-LLM 或 vLLM 這類框架是“發(fā)動機”負責把模型跑起來Kubernetes 是“機房管理員”負責管容器和節(jié)點而 Dynamo 是“車隊調度中樞”負責讓每一輛發(fā)動機驅動的車在正確的時間跑到正確的位置并提前規(guī)劃好所有路線的資源占用。在官方介紹里Dynamo 通常被描述為“用于 AI 推理的分布式中間層”它允許你描述整個推理服務的邏輯拓撲再由它映射到物理 GPU 集群上。它能夠管理多節(jié)點下的預處理、上下文處理Context 階段和生成階段Generation 階段也可以在 GPU 之間自動復制和放置模型同時還負責收集 KV Cache 等運行時遙測數(shù)據(jù)用于智能調度。我最早看到這個項目時的感覺是這其實是在把 Google 在大型系統(tǒng)里常用的一些思路比如分階段調度、全局資源池、狀態(tài)感知調度真正下沉到 GPU 推理這個具體場景里。對于線上業(yè)務來說這意味著可以從“手工編排腳本 拍腦袋定并發(fā)上限”走向更精細的資源管控。1.3 這個項目適合誰看、能幫你解決什么問題如果你手頭只是部署一個很小的模型單張消費級顯卡就能跑那 Dynamo 的復雜度可能超出了你的需求。但如果你符合下面任意一條這個項目就值得認真研究你負責的大模型服務需要部署在 4 張以上 GPU 上并且經(jīng)常為“某幾張卡算力打滿、另外幾張卡閑著”而頭疼。你的在線服務需要同時支持多用戶并發(fā)請求變化劇烈比如白天業(yè)務高峰、深夜低峰。你的模型規(guī)模太大單卡顯存放不下需要做張量并行或流水線并行推理。你需要把 Prefill預填充即處理輸入 prompt 的階段和 Decode逐 token 生成的階段拆到不同的 GPU 或不同的 Node 上以提升整體吞吐。你希望用更少的 GPU 支撐更大的并發(fā)而不是不停擴機器。一句話總結如果你已經(jīng)在跟“分布式推理”死磕Dynamo 就是那個能讓你少寫很多調度代碼、少踩很多顯存坑的框架層工具。2. 整體設計與架構拆解Dynamo 是怎么把“一群 GPU”變成“一個 GPU”的2.1 分布式推理的三大并行策略DP、PP、EP要理解 Dynamo 的設計必須先理清并行策略。Dynamo 支持數(shù)據(jù)并行DP、流水線并行PP和專家并行EP而且允許你在同一個推理拓撲里混合使用這些策略。數(shù)據(jù)并行DP是最直觀的同一份模型放在多張卡上每張卡處理不同的請求。這種方式擴容簡單但每張卡都要有完整的模型權重顯存開銷大而且如果每個請求占用的 KV Cache 不均衡卡之間可能出現(xiàn)嚴重的“偏科”。流水線并行PP是把模型按層切成多段每張卡負責其中一段。請求像流水線一樣依次經(jīng)過各段。這種方式能放下單卡放不下的超大模型但因為請求是串行通過各階段的容易產生氣泡利用率不高。專家并行EP是 MoE混合專家模型的常用策略。把不同的專家Expert分布到不同 GPU 上每個 token 只激活其中一部分專家從而用更少的算力實現(xiàn)更大的模型容量。EP 的問題在于通信量巨大對互連帶寬要求極高。Dynamo 的做法是不強迫你選一種而是把整個推理服務拆成多個可獨立并行的邏輯單元。比如一個模型可以被切成兩份流水線同時每一份又做 2 路張量并行整體還可以放兩個副本來扛并發(fā)。這種多維度的組合能力是它區(qū)別于早期簡單推理框架的關鍵點。2.2 核心架構Prefill 與 Decode 的物理分離你可能在不少文章里見過“PD 分離”這個詞PD 就是 Prefill 和 Decode。傳統(tǒng)方式里一個請求進入 GPU 后先做 Prefill把用戶的 prompt 處理成 KV Cache然后進入 Decode 階段逐 token 生成回答。兩個階段的計算特征完全不同Prefill 是計算密集尤其是長 prompt 場景需要大量矩陣乘法GPU 算力能跑得很滿。Decode 是訪存密集每一步只生成一個 token但要把整個 KV Cache 讀一遍瓶頸在顯存帶寬。如果把兩者混在同一批 GPU 上互相干擾非常大。Preffill 想把算力吃滿Decode 又需要低延遲和帶寬最終結果就是兩個階段都跑得不舒服。Dynamo 的思路是把推理拓撲顯式地拆成Context 階段Prefill和Generation 階段Decode不同階段使用不同的 GPU 集合。你可以在一個拓撲文件里定義用 4 張卡跑 Prefill、8 張卡跑 Decode中間通過高效的張量傳輸把 KV Cache 從 Prefill 卡搬到 Decode 卡。這樣 Prefill 卡可以專心沖刺計算Decode 卡可以批量處理更多的生成請求整體吞吐自然就上來了。這種設計不是 Dynamo 憑空發(fā)明的行業(yè)內很多大廠已經(jīng)在實踐但 Dynamo 把它變成了一個相對通用的開源框架能力這大大降低了實現(xiàn)門檻。2.3 全局調度、KV Cache 管理與分布式內存池Dynamo 最出彩的部分我個人認為是對 KV Cache 的管理。KV Cache 是推理過程中“最貴”的動態(tài)資源它不像模型權重那樣固定不變而是隨著每個請求的生存周期被分配和釋放。傳統(tǒng)框架里KV Cache 被限制在某一塊 GPU 上請求一旦被調度到某張卡它的 KV Cache 就必須一直在那張卡上待著這會直接影響負載均衡。Dynamo 引入了一種更靈活的模型把 KV Cache 看作一個可尋址的分布式內存池并通過KV Cache Manager來統(tǒng)一管理。調度器可以基于 KV Cache 的具體位置來決定請求去哪個 GPU也可以為了負載均衡而主動搬移或復制緩存。這與傳統(tǒng)“局部性優(yōu)先”的調度思路很不一樣等于是在全局視角上重新分配內存資源。這里有兩點非常重要。第一KV Cache Manager 需要和推理引擎強綁定Dynamo 提供了對應的接口TensorRT-LLM 等引擎可以暴露 KV Cache 的實時索引第二調度決策必須足夠快因為請求的到達是毫秒級的如果調度器本身需要幾百毫秒才能算出結果那一切都白搭。Dynamo 的做法是讓調度盡量輕量化并利用異步通信來完成 KV Cache 狀態(tài)同步。2.4 為什么選擇“可編程的拓撲描述”而不是“寫死一套規(guī)則”Dynamo 有一個比較特別的設計它讓你用 Python 類來描述一個推理服務的拓撲比如繼承LLM或LLMNode基類定義 Prefill 和 Decode 的關系、權重如何加載、KV Cache 如何傳輸。這相當于把“分布式架構”本身變成了可以版本管理、動態(tài)修改的代碼。這么做的好處很明顯不同模型的推理模式差異巨大。一個 7B 的稠密模型和一個 405B 的 MoE 模型它們的顯存占用、通信熱點、最適并行方式完全不同。如果框架把架構寫死要么是某種模型表現(xiàn)好其他模型很別扭要么就是框架復雜度爆炸。可編程拓撲讓用戶自己掌握架構決策權Dynamo 負責把描述轉換為真實執(zhí)行。我在實際做系統(tǒng)時深有體會很多框架功能強大但你很難“告訴它”你的特別需求。Dynamo 這種讓用戶參與編排的方式對于有專門推理優(yōu)化團隊的公司來說是真正可落地的而不是只能照著默認模板跑。3. 核心細節(jié)解析與實操要點我該從哪里下手3.1 看懂的標志能說清 LLM、LLMNode、KV Cache Manager、Router 各干什么如果你去翻 Dynamo 的代碼倉庫或文檔會看到幾個核心抽象。先別急著寫代碼把這幾個概念搞明白后面就順了。LLM最上層的推理服務抽象。你配置它表示“我要部署一個完整的模型服務”。它內部會管理副本、并行方式、KV Cache 分配等。LLMNode核心的可編排節(jié)點抽象。一個 LLM 可以拆成多個 LLMNode典型場景就是PrefillNode和DecodeNode。每個節(jié)點可以獨立設置并行策略和 GPU 數(shù)量。KV Cache Manager負責 KV Cache 的分配、跟蹤、傳輸和釋放。Dynamo 通過它與推理引擎交互獲取 KV Cache 的索引并根據(jù)調度決策傳遞緩存數(shù)據(jù)。Router / Scheduler接收外部請求根據(jù)后端實例的負載、KV Cache 位置等動態(tài)將請求分發(fā)到合適的 GPU 或節(jié)點。這里要注意具體代碼 API 可能會隨版本更新而變但核心概念是穩(wěn)定的。你先理解“節(jié)點 全局資源管理 路由”這個三角關系再去看代碼完全不會迷路。3.2 KV Cache 的分布式傳輸核心難點與優(yōu)化思路PD 分離后一個請求的 KV Cache 需要從 Prefill 節(jié)點搬到 Decode 節(jié)點。這聽起來簡單真做起來卻很難因為 KV Cache 動輒幾百 MB 甚至上 GB。如果傳輸效率低網(wǎng)絡會變成瓶頸甚至比不分離開還慢。Dynamo 的解決方案我在分析源碼時看到幾個關鍵點。一是盡量復用顯存到顯存的直接傳輸避免“顯存 - 內存 - 網(wǎng)卡 - 遠端內存 - 遠端顯存”這種繞路二是采用分塊或流水線傳輸讓計算和通信重疊而不是等整個 KV Cache 全部傳完再開始生成三是盡可能讓請求路由到“KV Cache 已經(jīng)在附近”的節(jié)點以此減少跨機傳輸。這一點也引出一個實操經(jīng)驗不要把 KV Cache 傳輸參數(shù)當作默認值不管。如果你們的網(wǎng)絡是 100Gbps 和 400Gbps表現(xiàn)會差很多。你至少要為集群的帶寬特性做一次針對性壓測找出當前 PD 分離配置下 KV Cache 傳輸是否成了瓶頸。3.3 推理引擎的適配TensorRT-LLM、vLLM 如何接進來Dynamo 不是一個獨立的“全棧推理方案”它需要配合實際的推理引擎。目前最典型的組合是 Dynamo TensorRT-LLM因為兩者都是 NVIDIA 生態(tài)接口配合最順。但這不代表 vLLM 或其他框架不能用只是適配工作量取決于引擎是否暴露了 Dynamo 所需要的控制點。要理解適配需要什么可以從推理引擎的角度想引擎需要允許外部模塊創(chuàng)建和管理 KV Cache而不是自己內部封閉管理。引擎需要能接收來自 Dynamo 的調度指令并把結果返回給調度器。引擎需要能和 Dynamo 共享遙測數(shù)據(jù)比如每塊 GPU 的顯存余量、當前并發(fā)數(shù)、KV Cache 命中情況。我在實際使用中建議不要一上來就試圖在自定義引擎上對接 Dynamo。先用官方示例跑通理解接口語義再做深度集成。通常官方會提供一個比較完整的參考實現(xiàn)你對照著改是最靠譜的路子。3.4 從 API 到實際部署需要留意的基礎環(huán)境在動手部署之前有幾個基礎環(huán)境要心里有數(shù)NVIDIA Driver 和 CUDA保持較新版本Dynamo 依賴較新的 GPU 驅動能力尤其是顯存直接訪問和多租戶管理相關特性。NVIDIA 容器工具通常建議在容器里跑官方鏡像已經(jīng)預裝了大量依賴省去自己配環(huán)境的痛苦。網(wǎng)絡互連如果做多節(jié)點部署建議使用 RDMA 或 InfiniBand 網(wǎng)絡。RoCE 也能跑但延遲和帶寬穩(wěn)定性會略差。GPU 型號與顯存不同 GPU 的顯存帶寬差異直接決定 Decode 節(jié)點的吞吐上限選型時別只盯算力。這里沒有特別復雜的步驟但很多人會因為環(huán)境版本不一致而翻車。我的建議是直接用官方提供的 Docker 鏡像開啟一版確認跑通再遷移到自己的鏡像。這樣做排查問題時至少能分清是環(huán)境問題還是代碼問題。4. 實操過程與核心環(huán)節(jié)實現(xiàn)從零搭一個 PD 分離的推理服務4.1 第一步定義推理拓撲把 Prefill 和 Decode 拆開我會用一個非常簡化的偽代碼來說明如何定義拓撲。假設你只有兩個邏輯階段一個處理 Prefill一個處理 Decode。在 Dynamo 的框架體系里大致會長這樣class MyPrefillNode(LLMNode): def exec(self, inputs, kv_cache_manager): # 使用 TensorRT-LLM 等引擎執(zhí)行 prefill # 將生成的 KV Cache 注冊到 kv_cache_manager ... class MyDecodeNode(LLMNode): def exec(self, inputs, kv_cache_manager): # 根據(jù) kv_cache 索引讀取緩存 # 執(zhí)行自回歸生成 ... llm LLM() prefill_node MyPrefillNode( modelllama3-70b, enginetensorrt_llm, placementnode1, # 例如放到 node1 的 4 張 GPU parallel_strategy{tp: 4} ) decode_node MyDecodeNode( modelllama3-70b, enginetensorrt_llm, placementnode2, # 例如放到 node2 的 8 張 GPU parallel_strategy{tp: 8} ) llm.add_node(prefill_node) llm.add_node(decode_node) llm.start()這是為了讓你理解思路真實 API 比這復雜但基本邏輯如此。你把模型切分和放置邏輯寫清楚Dynamo 會根據(jù)這些信息去拉起進程、分配 GPU、建立連接。這里的一個關鍵決策點是tp 和 pp 的選擇。如果模型權重大于單卡顯存你至少需要 tp2 或 tp4但如果 tp 太大AllReduce 通信會成為瓶頸尤其是在單機內部 NVLink 可用時 tp8 是常見選擇跨機則要慎重。如果你拿不準可以先從單機 tp 全部打滿開始再逐步增加數(shù)據(jù)并行副本。4.2 第二步把 KV Cache 的管理權限交給 Dynamo這個環(huán)節(jié)特別容易踩坑。默認情況下TensorRT-LLM 或 vLLM 都有自己的 KV Cache 管理方式它們會自己規(guī)劃顯存池。但 Dynamo 需要獲取 KV Cache 的狀態(tài)來做全局調度所以你必須顯式地啟用“外部 KV Cache 管理”模式。以 TensorRT-LLM 為例大致要經(jīng)歷這么幾步在構建引擎時開啟 KV Cache 相關配置并確保運行時以可外部訪問的方式暴露 KV Cache 索引。在 Dynamo 端配置 KV Cache Manager指定緩存存儲的位置和傳輸方式。查詢或預先分配 KV Cache 的顯存池大小避免因為緩存塊不足導致請求排隊。我見過最多的問題就是KV Cache 管理器顯示的容量和實際引擎可用容量不一致結果部分請求直接被拒絕。原因通常是對齊參數(shù)沒配置好或者顯存池預留小了。穩(wěn)妥做法是先設置一個偏大的緩存池跑一段時間性能測試后再根據(jù)顯存余量調小。4.3 第三步啟動服務看監(jiān)控指標而不是只看日志服務啟動以后很多人習慣只看日志里有沒有報錯。但在分布式推理場景下日志只能告訴你“進程活著”無法告訴你“系統(tǒng)是否健康”。你需要看幾類關鍵指標GPU 利用率區(qū)分 Prefill 和 Decode 節(jié)點。如果 Prefill 節(jié)點利用率很低說明請求壓力不足如果長期打滿但請求還是排隊說明 Prefill 的并行度不夠。KV Cache 利用率緩存池是否經(jīng)常不夠用、是否有大量淘汰發(fā)生。如果頻繁淘汰會極大增加 Prefill 重復計算??绻?jié)點傳輸量如果 PD 分離后網(wǎng)絡傳輸量非常大優(yōu)先看是否路由到了錯誤的節(jié)點。首 token 延遲和生成延遲這兩個指標比總體延遲更值得盯。首 token 延遲高問題大多在 Prefill生成延遲高往往在 Decode 或顯存帶寬瓶頸。Dynamo 通常會暴露一些度量接口你也完全可以把這些數(shù)據(jù)接進 Prometheus 或 Grafana。但作為最初的評估nvidia-smi 配合自定義日志就夠了先把數(shù)據(jù)拿到手再談優(yōu)化。4.4 第四步壓測與容量規(guī)劃確定“要不要調大 Decode 節(jié)點”部署完成后一定要做系統(tǒng)性的壓測而不是只發(fā)兩個請求試試。我的建議是準備一組比較有代表性的請求數(shù)據(jù)短問題、長問題、短答案、長答案混合并發(fā)壓測。記錄四個數(shù)QPS、首 token 延遲、生成吞吐、平均生成速度。如果你發(fā)現(xiàn) Prefill 節(jié)點 GPU 利用率高Decode 節(jié)點顯存帶寬基本跑滿那說明資源分配合理。如果 Decode 節(jié)點大量空閑而 Prefill 節(jié)點已經(jīng)排隊多半是 Prefill 節(jié)點算力不夠需要增加 Prefill 節(jié)點數(shù)量。反過來如果 Decode 節(jié)點排隊嚴重而 Prefill 節(jié)點很閑就該加 Decode 節(jié)點。這種容量規(guī)劃思路比“無腦加卡”要科學得多。Dynamo 的價值也正在這里拓撲可以用代碼描述擴容時只需要調整節(jié)點數(shù)量重新部署而不需要重寫推理邏輯。5. 常見問題與排查技巧實錄我在踩坑中總結的經(jīng)驗5.1 問題一PD 分離之后整體延遲反而更高了這是最容易讓人打退堂鼓的問題。很多人拆了 Prefill 和 Decode 后發(fā)現(xiàn)首 token 延遲或總延遲不降反升。第一反應是“分離方案不行”但絕大多數(shù)情況下其實是網(wǎng)絡傳輸瓶頸。排查思路很簡單看 PD 之間 KV Cache 傳輸時間占比。如果是傳輸導致的延遲增加辦法有幾個優(yōu)先把 Prefill 和 Decode 節(jié)點放在同一臺物理機內利用 NVLink 傳輸而不是走以太網(wǎng)。開啟更高效的傳輸模式比如顯存到顯存的同步傳輸。讓 Router 將請求優(yōu)先調度到 “KV Cache 已經(jīng)存在” 的節(jié)點減少傳輸概率。另外PD 分離適合并發(fā)壓力大的場景。如果并發(fā)很低比如每秒只有幾個請求PD 分離帶來的收益遠遠蓋不過傳輸損耗。別為了追新技術而強行拆分。5.2 問題二GPU 之間的負載嚴重不均分布式推理系統(tǒng)最常見的問題是某一張卡跑滿其他卡在摸魚。我排查時通常按順序看是不是路由策略導致的。請求被固定打到某些節(jié)點而另外節(jié)點因為 KV Cache 位置原因長期空閑。是不是并行策略不合理。比如 tp8 時如果通信期間阻塞了計算卡間利用率必然不均。是不是 KV Cache 碎片化導致部分請求無法分配只能擠在少數(shù)節(jié)點上。解決時一是調整 Router 的負載均衡策略二是重新規(guī)劃 TP/PP 配置三是縮短 KV Cache 的“黏性”允許更多請求被路由到緩存未命中的節(jié)點用一定的重復計算換取全局均衡。5.3 問題三并發(fā)一上來顯存直接爆掉顯存爆掉通常是 KV Cache 池和模型權重之間的比例設置有問題。你要意識到顯存是有限的模型權重占一部分激活值占一部分KV Cache 占一部分。推理時哪部分膨脹都會導致 OOM。建議給 KV Cache 池設置合理上限同時確保推理引擎有顯存保護機制。另外不要忽略“請求長度”這個變量。如果業(yè)務中經(jīng)常出現(xiàn)超長輸入會導致單個請求占用的 KV Cache 異常巨大。你可以在網(wǎng)關層做請求長度限制也可以在 Dynamo 層設置最大 KV Cache 分配量。5.4 問題四新版本接口變了老代碼跑不起來Dynamo 還處于快速迭代期API 變動是比較常見的。我的經(jīng)驗是鎖定版本不要盲目升級。生產環(huán)境用固定的鏡像 tag。閱讀官方示例時注意版本分支不要直接拿 main 分支的代碼套到穩(wěn)定版上。升級前先本地重新跑官方示例確認沒有基礎 API 變化再動自己的代碼。聽起來是老生常談但我在實際項目中見過太多次因為 API 變動導致整個拓撲全部重寫的案例。6. 一些真實體會和進階擴展建議這套架構接近成型后我最大的體會是分布式推理優(yōu)化的天花板往往不在“模型算子”里而在“資源調度”和“數(shù)據(jù)流”上。Dynamo 能火起來是因為它把大家過去手工做的那些破事比如自己寫 KV Cache 管理、自己寫 PD 分離、自己寫請求路由通通抽象成了框架能力。你不需要跟每一行通信代碼較勁而是可以把精力放在業(yè)務量預估和拓撲調優(yōu)上。最后再分享一個小技巧如果你們的場景是典型的“大并發(fā)、長短請求混合”可以先不做太復雜的 EP 和 PP而是從 DP PD 分離開始。先把最直觀的負載不均問題解決掉再根據(jù)壓測數(shù)據(jù)考慮引入更精細的并行策略。分布式推理的優(yōu)化是一步一步“喂”出來的不存在一個萬能配置能適配所有模型和所有業(yè)務。把 Dynamo 提供的控制能力用起來然后建立“假設 - 壓測 - 調參 - 再壓測”的循環(huán)這才是最穩(wěn)的路。