編排)
NVIDIA 開源 srt-slurm把 GPU 推理服務(wù)的編排做到 SLURM 里先說一個(gè)判斷推理部署真正的瓶頸往往不是顯卡性能不夠而是 GPU 集群里“誰能用、怎么用、出了問題誰來管”這件事太亂了。單機(jī)跑大模型還好一旦上了多節(jié)點(diǎn)、多團(tuán)隊(duì)、多模型的集群環(huán)境手動(dòng)分配 GPU、手動(dòng)啟動(dòng)推理服務(wù)、手動(dòng)盯著進(jìn)程是否掛掉會(huì)迅速耗盡你的時(shí)間和耐心。NVIDIA 開源的 srt-slurm表面上是個(gè)調(diào)度工具本質(zhì)上是在把“靠人盯集群”變成“靠編排管服務(wù)”。我寫這篇文章是想把一個(gè)容易被忽略的視角說清楚很多團(tuán)隊(duì)已經(jīng)有 SLURM 集群也裝了 NVIDIA 驅(qū)動(dòng)推理服務(wù)也能跑起來但距離“像 K8s 那樣交付一個(gè)推理服務(wù)”還差一層編排能力。srt-slurm 正是補(bǔ)這層的東西。讀完全文你會(huì)理解它解決什么真實(shí)問題、適合什么場(chǎng)景也能拿到一套基于 SLURM 和 NVIDIA 推理服務(wù)的可落地配置思路。1. 推理部署和“編排”之間差的那一步先回到一個(gè)典型場(chǎng)景你有一個(gè) 8 卡的 GPU 服務(wù)器上面裝了 SLURM幾個(gè)算法工程師都在往里提交訓(xùn)練任務(wù)。突然有一天業(yè)務(wù)方說要部署一個(gè)線上推理服務(wù)要求 7x24 小時(shí)可用還要支持多個(gè)模型切換。這時(shí)候你會(huì)發(fā)現(xiàn)SLURM 默認(rèn)的工作模式是“作業(yè)”而不是“服務(wù)”。訓(xùn)練任務(wù)跑完就退出資源立刻釋放推理服務(wù)要長期運(yùn)行必須一直占著 GPU。如果用它跑一個(gè)srun --gresgpu:1 python run_infer.py一旦進(jìn)程被 OOM 殺死、節(jié)點(diǎn)重啟、或者 SLURM 回收了作業(yè)服務(wù)就沒了沒人知道你線上已經(jīng)中斷了一個(gè)小時(shí)。更麻煩的是服務(wù)發(fā)現(xiàn)和流量調(diào)度。一個(gè)分布式推理服務(wù)通常有多個(gè)副本前端需要一個(gè)入口把這些副本的地址聚合起來。SLURM 只負(fù)責(zé)把作業(yè)調(diào)度到節(jié)點(diǎn)上它不知道你的服務(wù)監(jiān)聽哪個(gè)端口、是不是還活著、要不要擴(kuò)容。這些原本屬于 Kubernetes 的能力在傳統(tǒng) HPC 集群里是缺失的。所以srt-slurm 的出現(xiàn)本質(zhì)上是在 SLURM 的“資源調(diào)度層”和推理服務(wù)的“業(yè)務(wù)交付層”之間加了一個(gè)翻譯器和調(diào)度大腦。它把“向 SLURM 提交作業(yè)”這件事抽象成“聲明一個(gè)推理服務(wù)”然后由這個(gè)編排層去處理在哪個(gè)分區(qū)分配 GPU啟動(dòng)哪個(gè)推理引擎vLLM、TensorRT-LLM、NVIDIA NIM 等服務(wù)啟動(dòng)后把地址注冊(cè)到哪里健康檢查失敗后自動(dòng)重啟作業(yè)結(jié)束后清理殘留進(jìn)程。這樣的設(shè)計(jì)非常適合已經(jīng)圍繞 SLURM 建立了資源管理體系的團(tuán)隊(duì)。你不需要推倒重來切換到 Kubernetes而是在現(xiàn)有集群上獲得接近云原生的服務(wù)化體驗(yàn)。2. 認(rèn)識(shí) srt-slurm它是什么解決什么問題從現(xiàn)有公開信息看srt-slurm 是一個(gè)圍繞“SLURM 編排 推理服務(wù)部署”定位的開源項(xiàng)目。具體縮寫的全稱目前公開材料不多理解它的時(shí)候不必糾結(jié)字面意思直接看它做的事更有價(jià)值讓 GPU 推理服務(wù)在 SLURM 集群上以聲明式、可編排的方式運(yùn)行。它的核心價(jià)值可以拆成三層。第一層是資源抽象。你把“我想跑一個(gè) Qwen2.5-7B 的推理服務(wù)需要 1 張 A100”這樣一句話寫成配置而不是自己去記哪臺(tái)機(jī)器有空閑、該提交什么 srun 命令。編排層會(huì)解析配置生成對(duì)應(yīng)的 SLURM 作業(yè)提交到正確的分區(qū)。第二層是服務(wù)生命周期管理。推理服務(wù)和普通批處理任務(wù)的差異在于它要長期存活。因此 srt-slurm 需要支持健康檢查、日志回灌、進(jìn)程守護(hù)、失敗重啟。服務(wù)啟動(dòng)后它會(huì)探測(cè)推理服務(wù)的 HTTP 端口確認(rèn)模型加載完成、API 可以響應(yīng)才認(rèn)為“部署成功”。第三層是入口與服務(wù)發(fā)現(xiàn)。當(dāng)一個(gè)推理服務(wù)跑起來之后外部怎么找到它這里面通常需要一個(gè)注冊(cè)機(jī)制把節(jié)點(diǎn) IP 端口 服務(wù)名寫入某個(gè)存儲(chǔ)中例如共享文件、Redis 或 Nacos。前端網(wǎng)關(guān)再從注冊(cè)中心拉取可用地址做轉(zhuǎn)發(fā)。拿它和 Kubernetes 對(duì)比會(huì)更好理解。Kubernetes 天生把“部署、服務(wù)、伸縮、自愈”放在一起SLURM 擅長的是排隊(duì)調(diào)度和 GPU 資源分配但對(duì)服務(wù)化能力支持較弱。srt-slurm 更像是給 SLURM 裝上了一個(gè)“在線服務(wù)模式”讓 HPC 管理員不需要改變底層作業(yè)調(diào)度習(xí)慣也能交付穩(wěn)定的推理服務(wù)。當(dāng)然并不是所有場(chǎng)景都適合它。如果你的團(tuán)隊(duì)對(duì) Kubernetes 已經(jīng)很熟且業(yè)務(wù)完全云原生化繼續(xù)用 KServe 這類方案可能更完整如果你的集群規(guī)模很小、只有一塊 GPU用手動(dòng)啟動(dòng)腳本也夠用。srt-slurm 最有價(jià)值的地方是那些“已經(jīng)有 SLURM、有多卡、有多個(gè)用戶、但缺少服務(wù)化工具”的中間地帶。3. 核心基礎(chǔ)SLURM 作業(yè)調(diào)度與 GPU 服務(wù)化的差異想用好 srt-slurm先要理解 SLURM 的基本模型以及推理服務(wù)為什么不能完全照搬訓(xùn)練作業(yè)的管理方式。SLURM 里有幾個(gè)最常見的概念分區(qū)partition把節(jié)點(diǎn)按用途分組比如gpu分區(qū)、cpu分區(qū)節(jié)點(diǎn)node是實(shí)際執(zhí)行作業(yè)的計(jì)算資源作業(yè)job是你提交的調(diào)度單元按狀態(tài)分為排隊(duì)PD、運(yùn)行R、結(jié)束CD、失敗F等。作業(yè)可以交互式運(yùn)行也可以批處理運(yùn)行。訓(xùn)練任務(wù)通常是一次性的我跑 1000 個(gè) epoch跑完就結(jié)束SLURM 自然回收資源。推理服務(wù)卻要求一直活著只要用戶不主動(dòng)下線它就要持續(xù)監(jiān)聽端口、接收請(qǐng)求。于是這里出現(xiàn)了幾個(gè)關(guān)鍵差異。第一個(gè)差異是資源占用模式。訓(xùn)練任務(wù)用完即釋放推理服務(wù)必須長期持有 GPU。在 SLURM 里長期作業(yè)一直占用節(jié)點(diǎn)會(huì)讓排隊(duì)時(shí)間變長所以需要給推理服務(wù)設(shè)立獨(dú)立的 QoS 或分區(qū)避免它和訓(xùn)練任務(wù)互相擠占。第二個(gè)差異是啟動(dòng)判定標(biāo)準(zhǔn)。訓(xùn)練任務(wù)啟動(dòng)后就開始計(jì)算談不上“服務(wù) ready”。推理服務(wù)則不同模型權(quán)重加載就要幾十秒到幾分鐘顯存分配完成后 HTTP 端口才會(huì)監(jiān)聽。編排層必須有能力判斷“這個(gè)服務(wù)是否真正可用”而不是只看進(jìn)程有沒有起來。第三個(gè)差異是故障恢復(fù)。訓(xùn)練任務(wù)掛了可以重新排隊(duì)用戶能等推理服務(wù)掛了線上的請(qǐng)求直接失敗。所以 srt-slurm 這類編排層必須做自動(dòng)重啟、健康檢查和異常通知甚至要考慮把服務(wù)調(diào)度到其他健康節(jié)點(diǎn)上。下面用一個(gè)表格把這兩類作業(yè)的差異列清楚對(duì)比維度傳統(tǒng) SLURM 作業(yè)推理服務(wù)化作業(yè)生命周期短暫跑完即退長期駐留持續(xù)對(duì)外提供服務(wù)資源占用任務(wù)結(jié)束自動(dòng)釋放長期持有 GPU需要獨(dú)立配額管理成功標(biāo)準(zhǔn)進(jìn)程正常退出、產(chǎn)生產(chǎn)物HTTP 端口可訪問、模型可響應(yīng)重啟策略失敗后手動(dòng)重新提交失敗自動(dòng)拉起或重新調(diào)度訪問方式用戶通過文件和日志獲取結(jié)果通過 API 或網(wǎng)關(guān)訪問服務(wù)監(jiān)控需求任務(wù)日志、資源利用率端口健康、請(qǐng)求延遲、并發(fā)量、GPU 顯存從這個(gè)表可以看出srt-slurm 要做的就是把第二列的能力補(bǔ)齊。它本身并不是取代 SLURM而是讓 SLURM 從“批處理調(diào)度器”升級(jí)成“混合負(fù)載調(diào)度器”。4. 環(huán)境準(zhǔn)備與前置條件srt-slurm 的具體部署方式以官方倉庫 README 為準(zhǔn)但整體環(huán)境依賴通常包含以下幾個(gè)部分。這里我給出的是通用檢查思路你只要按這套清單核對(duì)基本不會(huì)走偏。4.1 基礎(chǔ)組件清單需要準(zhǔn)備的核心組件如下SLURM 集群包括slurmctld控制節(jié)點(diǎn)和slurmd計(jì)算節(jié)點(diǎn)版本建議使用當(dāng)前主流的大版本避免過老版本缺少關(guān)鍵特性。NVIDIA GPU 節(jié)點(diǎn)包含 NVIDIA 驅(qū)動(dòng)、CUDA 運(yùn)行環(huán)境以及 NVIDIA Container Toolkit。推理引擎vLLM、TensorRT-LLM、NVIDIA NIM 或其他兼容 OpenAI API 的推理服務(wù)。模型文件放在所有計(jì)算節(jié)點(diǎn)都能訪問的位置一般是共享存儲(chǔ)。服務(wù)發(fā)現(xiàn)組件可能是共享文件、Redis、etcd 等取決于 srt-slurm 的實(shí)現(xiàn)。4.2 檢查 SLURM 集群狀態(tài)在管理節(jié)點(diǎn)上執(zhí)行sinfo squeue預(yù)期的輸出應(yīng)該能看到節(jié)點(diǎn)處于idle或mix狀態(tài)并且有可用的 GPU partition。如果節(jié)點(diǎn)狀態(tài)是down或drain需要先恢復(fù)節(jié)點(diǎn)。scontrol show nodes scontrol show partition這些命令可以幫助你確認(rèn)節(jié)點(diǎn) GPU 配置和分區(qū)名稱。后面的編排配置里要寫對(duì) partition否則作業(yè)會(huì)一直排隊(duì)。4.3 檢查 GPU 與容器運(yùn)行時(shí)在被調(diào)度的 GPU 節(jié)點(diǎn)上執(zhí)行nvidia-smi nvidia-smi -L確認(rèn)驅(qū)動(dòng)已正確加載。如果要在容器里跑推理還需要安裝 NVIDIA Container Toolkit。Ubuntu 系統(tǒng)下典型的安裝步驟是curl -s -L https://nvidia.github.io/libnvidia-container/gpgkey | sudo apt-key add - curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list sudo apt-get update sudo apt-get install -y nvidia-container-toolkit sudo nvidia-ctk runtime configure --runtimedocker sudo systemctl restart docker如果你的環(huán)境無法訪問外網(wǎng)需要把上面的軟件源替換成內(nèi)部鏡像源。安裝完成后用這條命令驗(yàn)證容器能否識(shí)別 GPUdocker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi如果能看到類似nvidia-smi的輸出說明容器里的 GPU 透傳沒有問題。這一步非常關(guān)鍵因?yàn)?srt-slurm 在計(jì)算節(jié)點(diǎn)上很可能是通過容器拉起推理服務(wù)的。5. 從“手動(dòng)啟動(dòng)推理服務(wù)”到“編排提交”我們先看一個(gè)最原始的推理服務(wù)啟動(dòng)方式再逐步過渡到編排模型這樣你才能理解 srt-slurm 到底幫你省了什么。5.1 手動(dòng)啟動(dòng)推理服務(wù)在 GPU 節(jié)點(diǎn)上手動(dòng)執(zhí)行python3 -m vllm.entrypoints.openai.api_server \ --model /models/Qwen2.5-7B-Instruct \ --tensor-parallel-size 1 \ --host 0.0.0.0 \ --port 8000這樣服務(wù)確實(shí)能跑但你有幾個(gè)問題沒法解決如果機(jī)器重啟服務(wù)不會(huì)自動(dòng)拉起如果服務(wù)崩潰沒人幫你重啟端口被占用時(shí)只能手動(dòng)改配置多副本時(shí)沒有入口聚合前端只能寫死 IP。5.2 用 SLURM 作業(yè)提交推理服務(wù)把上面的命令寫進(jìn) SLURM 作業(yè)腳本可以在一定程度上解決“誰在跑”的問題#!/bin/bash #SBATCH --job-namemanual-infer #SBATCH --partitiongpu #SBATCH --gresgpu:1 #SBATCH --cpus-per-task8 #SBATCH --time01:00:00 #SBATCH --outputslurm-%j.out python3 -m vllm.entrypoints.openai.api_server \ --model /models/Qwen2.5-7B-Instruct \ --tensor-parallel-size 1 \ --host 0.0.0.0 \ --port 8000然后用sbatch提交sbatch start_infer.sh squeue這是“作業(yè)方式”的推理服務(wù)。它能保證服務(wù)在不出錯(cuò)的情況下長期運(yùn)行但離完善的“編排”仍然很遠(yuǎn)。你仍然要手動(dòng)查作業(yè)日志手動(dòng)處理端口沖突還要在服務(wù)崩潰后重新提交作業(yè)。5.3 用 srt-slurm 聲明推理服務(wù)到了 srt-slurm 這一層你不再直接寫 SLURM 腳本而是寫一份服務(wù)聲明由工具轉(zhuǎn)換成作業(yè)并持續(xù)維護(hù)。下面是一個(gè)演示性質(zhì)的思路# 示例命令具體參數(shù)以官方 README 為準(zhǔn) srt-slurm submit \ --name qwen-infer \ --model /models/Qwen2.5-7B-Instruct \ --engine vllm \ --partition gpu \ --gpu 1 \ --port 18000 \ --health-path /health提交后編排層會(huì)做幾件事自動(dòng)計(jì)算合適的 SLURM 參數(shù)、向集群提交作業(yè)、輪詢服務(wù)端口、確認(rèn)/health返回 200然后把服務(wù)的訪問地址注冊(cè)到服務(wù)發(fā)現(xiàn)中心。整個(gè)過程你提供的只是“服務(wù)意圖”而不是“機(jī)器命令”。6. 完整示例與代碼實(shí)現(xiàn)下面給出一套完整的、可以在真實(shí) SLURM 集群上落地的推理服務(wù)編排示例。這個(gè)示例不完全等同于 srt-slurm 的內(nèi)部實(shí)現(xiàn)但它包含了所有關(guān)鍵環(huán)節(jié)你理解之后再看官方文檔會(huì)非???。6.1 模型目錄準(zhǔn)備假設(shè)模型已經(jīng)放在共享存儲(chǔ)/models/Qwen2.5-7B-Instruct。如果 srt-slurm 會(huì)派發(fā)作業(yè)到不同節(jié)點(diǎn)那么所有計(jì)算節(jié)點(diǎn)必須都能訪問這個(gè)路徑。路徑掛載不一致是推理服務(wù)啟動(dòng)失敗最常見的原因之一。6.2 編寫服務(wù)聲明文件假設(shè)編排工具支持 YAML 聲明服務(wù)定義可能長這樣# 文件路徑services/qwen-infer.yaml name: qwen-infer engine: vllm model: /models/Qwen2.5-7B-Instruct partition: gpu gpu: 1 cpus: 8 timeout: 7200 port: 18000 replicas: 2 healthcheck: path: /health interval: 10 timeout: 5 retries: 3字段含義如下name服務(wù)名稱在集群內(nèi)唯一。engine推理框架例如vllm、tensorrt-llm或nim。model模型路徑。partitionSLURM 分區(qū)。gpu每個(gè)副本申請(qǐng)的 GPU 卡數(shù)。replicas服務(wù)副本數(shù)用于高可用。port服務(wù)對(duì)外暴露的端口。healthcheck健康檢查規(guī)則用于判斷服務(wù)是否 ready。再次提醒具體字段名以官方實(shí)現(xiàn)為準(zhǔn)這里的意義在于讓你理解“聲明式”長什么樣。6.3 提交服務(wù)假設(shè) CLI 工具名為srt-slurmsrt-slurm apply -f services/qwen-infer.yaml srt-slurm list srt-slurm status qwen-infer預(yù)期行為是list能看到服務(wù)處于running或deploying狀態(tài)status能顯示每個(gè)副本所在的 SLURM 作業(yè) ID 和節(jié)點(diǎn)地址。6.4 在 SLURM 節(jié)點(diǎn)上實(shí)際運(yùn)行的作業(yè)腳本如果不依賴編排工具直接用 SLURM 腳本模擬單副本推理服務(wù)腳本如下#!/bin/bash #SBATCH --job-nameqwen-infer-1 #SBATCH --partitiongpu #SBATCH --gresgpu:1 #SBATCH --cpus-per-task8 #SBATCH --time02:00:00 #SBATCH --output/var/log/slurm/qwen-infer-%j.out #SBATCH --error/var/log/slurm/qwen-infer-%j.err echo JOB_START_TIME$(date) nvidia-smi python3 -m vllm.entrypoints.openai.api_server \ --model /models/Qwen2.5-7B-Instruct \ --tensor-parallel-size 1 \ --host 0.0.0.0 \ --port 18000 \ --served-model-name qwen2.5-7b-instruct echo JOB_END_TIME$(date)提交sbatch scripts/start_infer.sh6.5 服務(wù)調(diào)用驗(yàn)證等到作業(yè)運(yùn)行后先看服務(wù)是否監(jiān)聽端口squeue scontrol show job JOB_ID ss -lntp | grep 18000在能訪問該節(jié)點(diǎn)的機(jī)器上執(zhí)行curl http://NODE_IP:18000/v1/models如果返回模型列表說明推理服務(wù)已經(jīng)就緒。再發(fā)一個(gè)對(duì)話請(qǐng)求curl http://NODE_IP:18000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: qwen2.5-7b-instruct, messages: [{role: user, content: 用一句話解釋為什么推理服務(wù)需要編排}], max_tokens: 128 }正常響應(yīng)中應(yīng)該包含choices字段并且?guī)С錾傻奈谋尽?.6 服務(wù)發(fā)現(xiàn)與網(wǎng)關(guān)接入在生產(chǎn)環(huán)境前端不可能寫死節(jié)點(diǎn) IP。更合理的做法是把每個(gè)副本的地址寫入 Redisredis-cli HSET srt:services:qwen-infer node-0 10.0.1.20:18000 redis-cli HSET srt:services:qwen-infer node-1 10.0.1.21:18000然后 API 網(wǎng)關(guān)或者 Nginx 從 Redis 拉取地址列表做負(fù)載均衡。這一步可以很輕量不一定需要引入完整的注冊(cè)中心。7. 運(yùn)行結(jié)果與效果驗(yàn)證跑通這套流程后你應(yīng)該按順序驗(yàn)證幾件事。7.1 作業(yè)狀態(tài)sinfo看到節(jié)點(diǎn)被分配squeue看到作業(yè)從PD變成Rsqueue -u $USER狀態(tài)為R表示作業(yè)正在運(yùn)行PD表示還在排隊(duì)。如果一直停在PD說明資源不足或你寫的分區(qū)名稱不對(duì)。7.2 服務(wù)端口在作業(yè)所在節(jié)點(diǎn)上確認(rèn)端口監(jiān)聽ss -lntp | grep 18000 curl http://127.0.0.1:18000/health如果配置了/health探針應(yīng)該返回 200。7.3 日志驗(yàn)證日志是排查問題的第一手信息tail -n 50 /var/log/slurm/qwen-infer-JOB_ID.err常見的日志內(nèi)容包括模型加載過程、tokenizer 配置、顯存分配以及最終的Application startup complete??吹竭@個(gè)信息說明服務(wù)已經(jīng)就緒。7.4 失敗后的第一步排查如果服務(wù)處于異常狀態(tài)第一步先把“異?!倍x清楚作業(yè)有沒有啟動(dòng)看squeue容器或進(jìn)程有沒有崩潰看作業(yè)日志GPU 是否可見在節(jié)點(diǎn)上跑nvidia-smi端口是否被占用看ss -lntp模型路徑是否可讀在節(jié)點(diǎn)上執(zhí)行l(wèi)s /models/Qwen2.5-7B-Instruct。大多數(shù)問題都出在這五個(gè)環(huán)節(jié)里。如果一個(gè)一個(gè)排查完還找不到原因再去翻 srt-slurm 控制端的日志。8. 常見問題與排查思路問題現(xiàn)象可能原因排查方式解決方案作業(yè)一直停在 PD 狀態(tài)分區(qū)無空閑 GPU或資源配額不足sinfo查看節(jié)點(diǎn)狀態(tài)squeue查看排隊(duì)情況等待資源釋放調(diào)整分區(qū)降低申請(qǐng)卡數(shù)服務(wù)啟動(dòng)后 HTTP 接口無法訪問服務(wù)監(jiān)聽地址不是0.0.0.0端口沒有暴露ss -lntp查看監(jiān)聽地址curl 127.0.0.1 測(cè)試設(shè)置--host 0.0.0.0檢查防火墻和安全組容器內(nèi)執(zhí)行 nvidia-smi 報(bào)錯(cuò)NVIDIA Container Toolkit 未安裝或未配置nvidia-container-cli info安裝 Toolkit確認(rèn) docker runtime 已配置模型加載非常慢冷啟動(dòng)加載權(quán)重共享存儲(chǔ)吞吐不足查看作業(yè)日志中的加載耗時(shí)預(yù)熱模型使用本地緩存增大存儲(chǔ)帶寬服務(wù)啟動(dòng)后立刻報(bào) OOM模型參數(shù)量超出單卡顯存查看dmesg和作業(yè)日志切換量化版本設(shè)置--tensor-parallel-size健康檢查失敗服務(wù)仍在加載模型探活超時(shí)時(shí)間過短curl 手動(dòng)訪問 /health查看服務(wù)日志延長健康檢查超時(shí)增加重試次數(shù)端口沖突多個(gè)服務(wù)申請(qǐng)了同一端口ss -lntp看端口占用情況讓編排層分配動(dòng)態(tài)端口建立端口分配表節(jié)點(diǎn)重啟后服務(wù)沒有恢復(fù)編排層未配置自動(dòng)重啟scontrol show job查看作業(yè)狀態(tài)配置自動(dòng)重啟策略結(jié)合 systemd 守護(hù)每個(gè)問題都不要只盯著表象。比如端口沖突根因可能是編排層沒有做端口分配也可能是你手動(dòng)啟動(dòng)了一個(gè)殘留進(jìn)程。先把“現(xiàn)在誰在監(jiān)聽這個(gè)端口”查清楚再?zèng)Q定殺掉哪個(gè)進(jìn)程。9. 最佳實(shí)踐與工程建議推理服務(wù)編排上了生產(chǎn)環(huán)境不能只看“能跑通”。下面這些實(shí)踐是我在同類系統(tǒng)里反復(fù)驗(yàn)證過值得投入的環(huán)節(jié)。9.1 服務(wù)定義盡量聲明式把服務(wù)名稱、模型路徑、GPU 數(shù)量、分區(qū)、端口寫成配置而不是散落在 shell 歷史記錄里。這樣團(tuán)隊(duì)其他成員能直接看到集群里有哪些服務(wù)、用的什么模型、占了多少資源。9.2 固定端口和動(dòng)態(tài)端口要有規(guī)則小規(guī)模集群可以約定端口段比如18000-19000歸推理服務(wù)使用規(guī)模再大一點(diǎn)最好由編排層統(tǒng)一分配。否則時(shí)間一長端口沖突會(huì)變成每日問題。9.3 所有推理服務(wù)必須暴露健康檢查接口vLLM 默認(rèn)提供/health端點(diǎn)TensorRT-LLM 和 NVIDIA NIM 也有對(duì)應(yīng)的探活方式。這是編排層判斷服務(wù)是否需要重啟的唯一可靠依據(jù)。沒有健康檢查自動(dòng)拉起就無從談起。9.4 日志不能只留在節(jié)點(diǎn)本地SLURM 作業(yè)日志默認(rèn)寫在計(jì)算節(jié)點(diǎn)節(jié)點(diǎn)一旦故障日志就丟了。建議將所有推理服務(wù)的日志發(fā)送到集中采集系統(tǒng)例如 Elasticsearch、Loki 或云日志服務(wù)。這樣在排障時(shí)不需要先定位節(jié)點(diǎn)再翻文件。9.5 網(wǎng)絡(luò)暴露必須做認(rèn)證如果你通過 srt-slurm 暴露推理 API不要把端口直接開放到公網(wǎng)。建議前置一層認(rèn)證網(wǎng)關(guān)例如使用 API Key、OIDC 認(rèn)證或者至少做 IP 白名單。無認(rèn)證的推理服務(wù)在公網(wǎng)上會(huì)很快被掃描和惡意調(diào)用這個(gè)風(fēng)險(xiǎn)不是危言聳聽。9.6 給推理服務(wù)設(shè)置獨(dú)立的 QoS 或分區(qū)訓(xùn)練作業(yè)通常是高吞吐、短時(shí)間、可排隊(duì)推理服務(wù)是長期占用、低延遲、不能排隊(duì)。兩類負(fù)載混在一個(gè)分區(qū)里會(huì)導(dǎo)致推理服務(wù)被訓(xùn)練作業(yè)擠到后面延遲不穩(wěn)定。最好單獨(dú)設(shè)置一個(gè)infer分區(qū)配合 SLURM QoS 限制最長運(yùn)行時(shí)間或最大并發(fā)數(shù)。9.7 預(yù)留模型預(yù)熱策略大模型冷啟動(dòng)時(shí)間較長。如果服務(wù)頻繁重建調(diào)用方會(huì)一直看到超時(shí)。一種做法是把服務(wù)常駐并定期探活另一種是啟動(dòng)腳本里先向模型發(fā)送一個(gè)最小請(qǐng)求完成預(yù)熱再注冊(cè)到服務(wù)發(fā)現(xiàn)中心。后者在自動(dòng)擴(kuò)容場(chǎng)景下非常有用。9.8 用 Prometheus 監(jiān)控 GPU 和延遲NVIDIA 提供了dcgm-exporter可以采集 GPU 利用率、顯存、溫度等指標(biāo)。推理服務(wù)層面可以暴露請(qǐng)求延遲、QPS、token 吞吐。把這些接入 Prometheus Alertmanager一旦 GPU 利用率異常或 P95 延遲升高就能第一時(shí)間收到告警。10. 總結(jié)與后續(xù)學(xué)習(xí)方向srt-slurm 這類項(xiàng)目的價(jià)值不是提供一個(gè)又一個(gè)炫酷命令而是把 GPU 推理服務(wù)的運(yùn)行方式從“腳本 人工盯”變成“聲明 編排自動(dòng)維護(hù)”。它適合那些已經(jīng)有 SLURM 集群、想在不動(dòng)底層調(diào)度系統(tǒng)的情況下獲得服務(wù)化能力的團(tuán)隊(duì)。如果你正在搭大模型推理平臺(tái)可以重點(diǎn)關(guān)注它如何處理作業(yè)聲明、健康檢查、服務(wù)發(fā)現(xiàn)和自動(dòng)重啟四個(gè)環(huán)節(jié)。下一步的實(shí)踐建議很直接先準(zhǔn)備一個(gè)兩節(jié)點(diǎn)的 SLURM 測(cè)試環(huán)境裝好 NVIDIA Container Toolkit用 vLLM 跑通一個(gè)最小推理服務(wù)再對(duì)照 srt-slurm 官方倉庫的 README把這里描述的通用概念映射到具體命令上。不用一上來就追求多副本和高可用能把“提交一個(gè)服務(wù)、自動(dòng)拉起、API 可通、失敗能重啟”這條鏈路跑通就已經(jīng)離生產(chǎn)環(huán)境很近了。把這篇文章收藏下來動(dòng)手實(shí)驗(yàn)時(shí)遇到“作業(yè)排隊(duì)、服務(wù)端口不通、容器不識(shí) GPU、健康檢查失敗”四類問題回來對(duì)照第 8 節(jié)的排查表基本能省下不少找資料的功夫。