設施實戰(zhàn):GPU算力調(diào)度與推理服務優(yōu)化)
今天正式加入 Dynamia 密瓜智能以后很長一段時間我都會泡在 AI 原生基礎(chǔ)設施這條線上。熟悉我的朋友都知道過去幾年我主要做分布式系統(tǒng)和云原生架構(gòu)接過不少訓練平臺、推理服務的活但這次不是換個公司繼續(xù)干老本行而是要把“基礎(chǔ)設施”這個東西重新拆開站在 AI 的視角再組裝一遍。這篇文章就當我的開工筆記把決定加入前后的思考、對 AI 原生基礎(chǔ)設施的理解以及最近實操踩出來的經(jīng)驗一并寫清楚。如果你也在做模型訓練、推理服務或者正在幫團隊搭 GPU 算力平臺這篇文章應該能給你一些參考。哪怕你現(xiàn)在只是剛接觸大模型只要搞明白“算力、存儲、網(wǎng)絡、調(diào)度、服務”這幾件事怎么協(xié)作后面看任何 AI Infra 相關(guān)的方案都會輕松很多。1. 為什么我從“跑模型”轉(zhuǎn)到“AI 原生基礎(chǔ)設施”先說結(jié)論傳統(tǒng)云原生基礎(chǔ)設施解決的是“應用怎么跑得穩(wěn)”AI 原生基礎(chǔ)設施解決的是“模型怎么跑得快、跑得省、跑得起”。這倆看起來都是基礎(chǔ)設施但底層邏輯完全不同。我過去搭過不少 Kubernetes 集群也幫團隊做過微服務改造。那時候的核心關(guān)注點是容器的生命周期、配置管理、服務發(fā)現(xiàn)、彈性伸縮。一個典型場景是用戶請求量漲了HPA 自動把 Pod 從 3 個擴到 10 個流量降了再縮回來。這套體系放在 Web 服務上非常成熟OpenTelemetry、Prometheus、Ingress Controller 一套組合拳打下來基本能覆蓋 90% 的運維需求。但放到 AI 場景里這套邏輯立刻露餡Web 請求是無狀態(tài)的模型推理請求是有狀態(tài)的。一個模型加載到顯存里可能要幾十秒甚至幾分鐘Pod 副本數(shù)隨便擴容沒有任何問題但模型副本不能隨便擴顯存不夠就是不夠GPU 卡不插上去就不存在。Web 流量高峰可以排隊推理請求排隊需要額外管理。用戶可等不了一個整 Batch 慢慢湊延遲敏感業(yè)務對 P99 的要求近乎苛刻。Web 資源可以按 CPU/內(nèi)存配額切分GPU 資源的切分顆粒度又貴又粗顯存、算力、帶寬彼此還會互相影響。換句話說云原生基礎(chǔ)設施是“以容器為中心”AI 原生基礎(chǔ)設施是“以模型和 GPU 為中心”。倒不是說 K8s 在 AI 場景沒用而是光靠 K8s 那一套遠遠不夠你得在它上面重新設計一層面向模型、面向計算資源、面向數(shù)據(jù)流的邏輯。1.1 AI 原生基礎(chǔ)設施到底和“云原生 GPU”差在哪很多團隊以為在 K8s 里加上 GPU 節(jié)點就能做 AI 平臺其實差距挺大的。我做了一張對照表能比較清楚地看到兩者的差異維度云原生基礎(chǔ)設施AI 原生基礎(chǔ)設施調(diào)度對象容器 / PodGPU 資源、顯存、模型副本彈性單位實例副本數(shù)批量推理任務、動態(tài) Batch、顯存配額故障恢復重啟容器重新加載權(quán)重、檢查點恢復、斷點續(xù)訓存儲需求低延遲熱數(shù)據(jù) 返回數(shù)據(jù)超大模型文件、Checkpoint、數(shù)據(jù)集多渠道讀寫網(wǎng)絡瓶頸微服務調(diào)用梯度同步、KV Cache 傳輸、分布式推理成本敏感點實例單價 / 并發(fā)GPU 利用率、排隊等待、混合任務調(diào)度這也解釋了為什么現(xiàn)在大家開始反復提“AI 原生”而不是簡單說“在 K8s 上跑 AI”。前者是從頭按 AI 工作負載的形狀來設計基礎(chǔ)設施后者只是把 AI 工作負載硬塞進原有的基礎(chǔ)設施。1.2 這個賽道解決什么問題加入 Dynamia 密瓜智能之前我和團隊聊過幾次最終真正說服我的不是 PPT是三個具體問題第一算力利用率太難看。很多公司的 GPU 集群平均利用率不到 30%。訓練任務白天跑推理服務晚上高峰中間還有大量碎片時間。把訓練和推理放在同一個池子里動態(tài)調(diào)度聽上去簡單做起來涉及 GPU 共享、顯存隔離、搶占策略每一步都是硬骨頭。第二大模型推理的延遲瓶頸。模型越來越大顯存放不下得做量化、蒸餾、分布式推理。推理框架選型、動態(tài) Batch 調(diào)參、前置網(wǎng)關(guān)怎么做直接影響用戶體驗和成本。第三數(shù)據(jù)流轉(zhuǎn)效率。訓練前期要讀海量數(shù)據(jù)集訓練過程中要高頻寫 Checkpoint訓練完又要發(fā)布模型到推理集群。整個鏈條上如果存儲和緩存設計不合理GPU 再快也在等數(shù)據(jù)時干燒電。這三個問題背后其實是同一個核心把 GPU 當成一種需要精細調(diào)度的稀缺資源而不是可以隨便鋪的普通服務器。這也是 Dynamia 密瓜智能想做透的事。2. 一套 AI 原生基礎(chǔ)設施的“最小五件套”如果你也要從零搭一套 AI 原生基礎(chǔ)設施我的建議是先別急著上各種高級組件而是把下面五層搞清楚。這五層是一個可運行的最小骨架之后所有平臺能力都是在這五層之上逐步長出來的。2.1 算力層GPU 節(jié)點選型與配置算力層很容易被理解成“買卡就行”實際遠不止。GPU 節(jié)點配置要同時考慮三件事GPU 型號、CPU/內(nèi)存配比、互聯(lián)拓撲。GPU 型號直接決定了你能跑多大的模型。以常見的單卡顯存為例一張卡 80GB 和一張卡 24GB 能承載的模型規(guī)模差非常多。顯存不夠就得做模型并行或者切分這會引入額外的通信開銷所以很多時候?qū)幙蛇x大顯存卡。CPU/內(nèi)存配比容易被忽略。數(shù)據(jù)預處理、Tokenize、動態(tài) Batch、Python 運行時這些都會吃 CPU 和內(nèi)存如果節(jié)點里 CPU 核數(shù)太少GPU 會經(jīng)常空等數(shù)據(jù)。我見過一個實例數(shù)據(jù)管道沒做好GPU 利用率只有 40%CPU 卻 100% 跑滿典型的一核有難、八核圍觀?;ヂ?lián)拓撲更關(guān)鍵。多卡訓練時卡與卡之間的通信帶寬直接決定了訓練效率。NVLink 和普通 PCIe 的帶寬差距可能是數(shù)量級的。選機器的時候我建議問清楚卡間互聯(lián)方式別光看卡數(shù)。至少要讓同一臺機器上的跨卡通信走高速互聯(lián)跨機通信再另外規(guī)劃 RDMA 或高性能網(wǎng)絡。2.2 存儲層模型倉庫、數(shù)據(jù)集與檢查點AI 場景的存儲需求和普通業(yè)務完全不同。一個模型權(quán)重文件動輒幾十 GBCheckpoint 可能要寫幾百 GB數(shù)據(jù)集又是大量小文件加少量超大文件混合。這時候很難用單一存儲方案通吃。我的建議是分層處理訓練數(shù)據(jù)用并行文件系統(tǒng)或者高性能對象存儲核心指標是高吞吐和大并發(fā)能扛住成百上千個數(shù)據(jù)加載進程同時讀。模型文件用對象存儲 本地緩存。推理節(jié)點啟動時先從對象存儲拉權(quán)重但每次都拉一遍顯然不現(xiàn)實所以節(jié)點上要有本地緩存層最好再配合模型預熱機制。Checkpoint 寫入用高帶寬并行存儲并且要有版本管理。訓練崩了要能快速回滾到最近一次健康狀態(tài)而不是從頭再來。存儲層最怕的是“看起來能存實際一壓就垮”。很多團隊一開始圖省事用了常規(guī)文件存儲結(jié)果并行訓練一開存儲帶寬直接被打滿訓練速度反而被存儲拖慢。這一塊不能省。2.3 網(wǎng)絡層分布式訓練與推理的隱形命脈模型規(guī)模一大單卡、單機都裝不下分布式是必然選擇。分布式訓練里最核心的通信模式是 AllReduce每一輪梯度同步都需要所有節(jié)點互相傳數(shù)據(jù)這種通信對帶寬和延遲極其敏感。普通以太網(wǎng)下幾百張卡一起同步開銷會迅速吃掉訓練收益。所以 AI 原生基礎(chǔ)設施的網(wǎng)絡設計重點不是對外提供多少帶寬而是內(nèi)部東西向流量的延遲和吞吐。RDMA 技術(shù)已經(jīng)是分布式訓練場景的事實標準。當然不是說沒有 RDMA 就跑不了分布式訓練而是規(guī)模上來之后這是繞不開的性能分水嶺。推理側(cè)的網(wǎng)絡壓力也開始變大?,F(xiàn)在很多團隊做 Prefill 和 Decode 分離把 Prefill 階段的中間結(jié)果通過高速網(wǎng)絡傳給 Decode 節(jié)點跨機傳輸?shù)臄?shù)據(jù)量比傳統(tǒng)請求大很多網(wǎng)絡設計必須提前考慮。2.4 調(diào)度與編排層誰來決定這塊 GPU 給誰用我在加入前最看重的就是這一層。沒有調(diào)度所有 GPU 資源就是一堆散落的算力談不上平臺。調(diào)度層首先要感知 GPU 資源。節(jié)點上有幾張卡、多少顯存空閑、是否已經(jīng)跑著任務都要能實時掌握。不能只看節(jié)點剩余 CPU 和內(nèi)存因為兩個節(jié)點即使 CPU 相同GPU 型號不同能跑的任務也完全不同。其次要支持多級調(diào)度策略。訓練任務通常跑得久、資源需求大推理任務需要快速響應、延遲敏感。這兩種任務混在同一個集群里需要一個能區(qū)分優(yōu)先級、能搶占、能排隊的調(diào)度器。比如高峰期的交互式推理請求應該優(yōu)先離線批量訓練可以排后。最后還要處理 GPU 共享和顯存隔離。一張卡上跑多個推理任務可以大幅提升利用率但顯存配額的硬隔離必須到位否則一個任務超顯存會把同卡上的其他任務一起打掛。2.5 接入層模型服務與推理網(wǎng)關(guān)模型訓練得再好最終要通過服務暴露出去才有價值。接入層是用戶第一眼看到的東西也是延遲和成本控制的關(guān)鍵戰(zhàn)場。我比較推薦的模式是“模型服務引擎 推理網(wǎng)關(guān)”兩層。模型服務引擎負責真正加載模型、執(zhí)行推理常見的有 vLLM、Triton 這類框架它們內(nèi)部已經(jīng)做了 PagedAttention、動態(tài) Batch 等優(yōu)化。推理網(wǎng)關(guān)則負責請求路由、鑒權(quán)、限流、排隊、超時管理相當于模型世界的 API Gateway。兩層分離的好處是引擎可以專注性能優(yōu)化網(wǎng)關(guān)可以專注接入邏輯。以后模型版本迭代比如從 7B 換到 13B只需要在網(wǎng)關(guān)層調(diào)整路由規(guī)則不需要改動整體接入鏈路。另外推理網(wǎng)關(guān)還承擔流控職責防止突發(fā)流量把模型服務打爆。3. 落地過程中的關(guān)鍵設計我偏向的四個選擇有了最小五件套的骨架接下來就是更細的設計選擇。這些選擇沒有絕對的對錯更多是結(jié)合業(yè)務形態(tài)做取舍。我這里把自己認為值得參考的四個決策點寫出來。3.1 訓練和推理共用集群而不是物理隔離很多團隊習慣把訓練集群和推理集群分開管理簡單但資源利用率很低。白天推理業(yè)務少的時候GPU 閑置著晚上訓練任務跑完算力又空著。分開部署兩邊都在浪費。我偏好的做法是訓練推理共用同一個資源池但用調(diào)度策略區(qū)分優(yōu)先級。交互式推理請求優(yōu)先級最高可以搶占低優(yōu)先級離線訓練任務離線訓練任務則把資源利用的空窗填滿。這個設計對調(diào)度器的要求高但收益也很直接同樣的 GPU 總量月產(chǎn)出至少多出兩成。3.2 GPU 共享用顯存硬隔離不用裸跑裸占一張 80GB 的卡如果只跑一個大模型內(nèi)存利用率太難看。我很看好 GPU 共享的方向但實現(xiàn)方式必須講究。硬件層面的 MIG 或者虛擬化方案能做到比較強的隔離一張卡切幾個實例互不干擾。軟件層面的時間切片能提升利用率但隔離性弱一個任務的異常容易殃及同卡鄰居。我的習慣是在生產(chǎn)環(huán)境用硬件級隔離或容器級顯存限制寧可單卡利用率低一點也要保證故障隔離和安全邊界。測試環(huán)境可以放開時間切片怎么壓都行。3.3 推理請求先排隊再動態(tài) Batch動態(tài) Batch 能大幅提升推理吞吐。原理很簡單把短時間內(nèi)的多個請求攢在一起湊成一個 Batch 喂給模型利用 GPU 的并行計算能力同時處理多個請求代價是第一個請求會稍微多等一會。這里的關(guān)鍵參數(shù)是 Batch 窗口。窗口太短攢不住請求Batch 效果不明顯窗口太長延遲飆升用戶體驗崩掉。我一般會從 20ms 起步調(diào)觀察 P99 延遲和吞吐曲線找到剪刀差最小的點。另一個調(diào)整方向是優(yōu)先聚合同類請求讓同一個 Batch 內(nèi)部模型保持一致避免不同模型來回切換導致緩存失效。3.4 模型發(fā)布要可回滾版本要可追溯模型上線之后不是萬事大吉。線上效果變差、數(shù)據(jù)分布漂移、推理結(jié)果異常都需要快速回滾到之前的版本。所以模型倉庫里的每個模型都要有版本號、訓練日志、評估指標發(fā)布時要走灰度流程。灰度推理是我比較強調(diào)的環(huán)節(jié)。先切 5% 流量到新模型觀察反饋確認沒問題再逐步放量。一旦異常指標出現(xiàn)網(wǎng)關(guān)層要能立刻切回舊版本。這個流程依賴模型網(wǎng)關(guān)的路由能力所以 2.5 里我特意強調(diào)網(wǎng)關(guān)的重要性。4. 從零跑通一個 AI 推理服務的實操記錄理論說了不少上點實操。最近我在 Dynamia 密瓜智能的測試環(huán)境里搭了一套最小推理服務從裸機到能調(diào)通接口大致花了一個下午。把過程寫下來給你一個可以照著做的模板。4.1 環(huán)境準備驅(qū)動、容器運行時、GPU 識別正常步驟是先裝 GPU 驅(qū)動再裝容器運行時最后讓 K8s 識別到 GPU 資源。如果只是單機驗證可以用 Docker 直接跑但生產(chǎn)環(huán)境建議還是走 K8s。這里重點檢查一件事容器里能不能看到 GPU。很多坑都出在驅(qū)動版本和容器運行時版本不匹配上。驗證命令很簡單跑一個帶 GPU 的測試容器執(zhí)行nvidia-smi能看到卡信息基本就通了。注意驅(qū)動裝完別忘了重啟節(jié)點。很多人漏了這一步結(jié)果nvidia-smi在宿主機上正常容器里怎么都看不到卡。4.2 部署模型服務引擎我這次用的是 vLLM 來加載模型。先拉一個精簡模型做起驗證配置核心參數(shù)時給兩點建議max-model-len不要設置太大。很多人喜歡把上下文窗口開滿實測下來顯存占用會明顯上升如果業(yè)務很少用到超長輸入設一個合理的值更經(jīng)濟。gpu-memory-utilization一般設 0.85 到 0.9。別設到 0.95 以上顯存接近滿載時碎片化問題會直接影響并發(fā)能力和穩(wěn)定性。模型服務引擎的啟動命令大概長這樣python -m vllm.entrypoints.openai.api_server \ --model /data/models/qwen2-7b-instruct \ --served-model-name qwen2-7b \ --max-model-len 8192 \ --gpu-memory-utilization 0.9 \ --port 8000啟動成功后可以用一個最簡單的請求驗證curl http://127.0.0.1:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: qwen2-7b, messages: [{role: user, content: 你好}] }能正常返回說明模型服務引擎已經(jīng)通了。4.3 加一層網(wǎng)關(guān)做路由和限流單機驗證沒問題接生產(chǎn)還需要在前面加網(wǎng)關(guān)。網(wǎng)關(guān)要處理的事情包括請求路由到正確的模型服務、接口鑒權(quán)、Token 限流、排隊超時等。這層我用的是比較通用的方案Kong 或者 APISIX 都可以。關(guān)鍵是配置路由規(guī)則把/v1/chat/completions的請求轉(zhuǎn)發(fā)到 vLLM 的 8000 端口并給每個調(diào)用方配好 QPS 上限。網(wǎng)關(guān)層我額外加了兩個參數(shù)連接超時和讀超時。模型推理比較慢超時設太短會誤殺正常請求設太長又會讓異常請求長期占據(jù)連接。我會把默認讀超時設成 120 秒因為長文本生成的耗時確實可能到分鐘級。最大排隊數(shù)。超出排隊上限直接返回 429 錯誤避免雪崩效應。這樣做之后調(diào)用方拿到的是一套穩(wěn)定的 API后端模型是哪個、要不要擴容調(diào)用方完全不用關(guān)心。4.4 壓測與指標觀察服務起來之后一定要壓測別直接上生產(chǎn)。我用的壓測工具是簡單的 locust 腳本構(gòu)造一批并發(fā)請求同時盯四個指標QPS、TTFT首 Token 延遲、Token 生成速率、GPU 利用率。第一輪壓測我通常會把并發(fā)從 1 逐步加到 50觀察延遲曲線。如果 QPS 不再線性增長說明系統(tǒng)進入瓶頸區(qū)再壓下去只會讓延遲劇增。這個瓶頸點的數(shù)據(jù)就是后續(xù)做容量評估和成本預估的依據(jù)。壓測結(jié)果出來后我會回到 3.3 提到的動態(tài) Batch 參數(shù)重新調(diào) Batch 窗口和并發(fā)限制。實測下來調(diào)優(yōu)后 QPS 翻倍是很常見的事。5. 最近踩過的三個真實坑再來點更接地氣的。下面的問題都是我在實操中真實遇到過的網(wǎng)上資料不太會這么集中地寫我整理出來給同行參考。5.1 GPU 顯存泄漏服務越跑越慢現(xiàn)象模型服務剛啟動時延遲很好跑兩三天后延遲逐漸變高最后 OOM 崩潰。排查過程先看進程內(nèi)存和顯存占用發(fā)現(xiàn)顯存使用率持續(xù)走高。再用 Nvidia 的調(diào)試工具抓 CUDA 緩存狀態(tài)確認是部分請求結(jié)束后沒有正確釋放顯存。常見誘因是自定義模型邏輯里創(chuàng)建了 CUDA 張量但沒有顯式清理或者某些庫版本存在內(nèi)存碎片問題。結(jié)論顯存泄漏問題很難完全避免但可以通過定期滾動重啟來止血更治本的做法是升級推理框架版本并確保模型代碼里的臨時張量都走with torch.cuda.device這類規(guī)范寫法。注意上線前壓測不要只壓 10 分鐘至少要壓幾個小時甚至幾天才能暴露出泄漏問題。很多人就是栽在短壓測看起來一切正常。5.2 高峰時段請求排隊過深P99 延遲爆炸現(xiàn)象業(yè)務高峰期 P99 延遲從 300ms 飆到 5 秒甚至出現(xiàn)調(diào)用超時。排查過程檢查網(wǎng)關(guān)日志發(fā)現(xiàn)高峰期排隊數(shù)非常大模型服務的 Batch 窗口又過長導致大量請求堆在等待隊列里。再往下查真實原因是模型副本數(shù)不夠GPU 資源上限到了加排隊只是把問題從“超時”變成長尾。結(jié)論合理的做法是高峰期自動擴容模型副本并設置最大排隊深度拒絕掉一些可接受的流量。不能只顧著保護后端無限制地堆積請求這樣會把所有用戶的體驗都拖差。5.3 多租戶任務互相干擾一個任務寫爆共享目錄現(xiàn)象同一個訓練集群里兩個團隊跑任務其中一個瘋狂寫臨時文件把共享存儲打滿導致另一個團隊的 Checkpoint 寫不進去。排查過程查存儲看是單個大文件占空間還是一堆小文件占 inode。這次更隱蔽單個文件不大但數(shù)量幾百萬個把共享目錄的 inode 打滿了。結(jié)論租戶隔離不只是算力隔離存儲配額和文件數(shù)限制也要做。我后來給每個租戶單獨目錄設置容量配額和文件數(shù)配額并對臨時文件做自動清理策略問題才徹底解決。癥狀可能原因解決辦法顯存持續(xù)上漲最終 OOM推理框架顯存泄漏未釋放緩存升級框架版本規(guī)范臨時張量清理定期滾動重啟P99 延遲飆升隊列堆積過深模型副本不足擴容副本設置最大排隊數(shù)和超時策略共享目錄空間或 inode 打滿租戶任務寫臨時文件無節(jié)制配置容量配額、文件數(shù)配額、自動清理請求偶發(fā)返回 500 或超時模型加載中壓測后冷啟動問題增加模型預熱機制用就緒探針控制流量多卡訓練速度上不去卡間通信走普通 PCIe帶寬不足改高速互聯(lián)優(yōu)化數(shù)據(jù)并行和梯度同步策略6. 我對接下來的方向判斷加入 Dynamia 密瓜智能之后我把未來一段時間的工作重點分成三個階段。第一個階段是把現(xiàn)有集群的利用率打上去通過細粒度的調(diào)度和副本管理先把空閑 GPU 盤活。第二個階段是把推理服務標準化給業(yè)務方提供一致的接入體驗內(nèi)部模型怎么部署、怎么灰度、怎么回滾都做成標準流程。第三個階段是更長期的事情做訓練推理一體化的資源編排讓一個資源池能同時支撐訓練和推理的復雜混合負載。這三個階段里我對第三個階段最感興趣。很多人覺得訓練和推理是兩個系統(tǒng)訓練平臺管分布式任務推理平臺管在線服務。但它們的底層資源明明是同一批 GPU。如果能把檢查點恢復、模型預熱、動態(tài)擴容這些能力整合到一個系統(tǒng)里AI 團隊從開發(fā)到上線再到迭代的效率會提升一個大的臺階。老實說這個方向沒人敢說完全做透了??ㄅc卡之間的調(diào)度、顯存與算力的隔離、存儲與網(wǎng)絡的配合每一個環(huán)節(jié)都有大量優(yōu)化空間。正因為如此這件事才值得認真做。這幾個月我自己最大的體會是AI 原生基礎(chǔ)設施不是買一堆卡然后寫個 Kubernetes 部署文件那么簡單它更像把算力當成一門生意來精細化運營。每一塊 GPU 的利用率、每一次推理的延遲、每一個任務的排隊時間最后都會變成實實在在的成本和用戶體驗。這個項目后續(xù)我能延展的東西還很多后面有新的進展或者踩到新坑再回來寫文章繼續(xù)跟大家聊。