Skip to content

服务部署架构:集群、路由与运维 ​

标签
AI/infra/推理引擎
AI/infra/部署
字数
4202 字
阅读时间
17 分钟

单个推理实例怎么跑,在 06-vLLM 部署、参数与服务特性;引擎之间的取舍也在那一篇。这一篇收的是一个实例之外的那一层 —— 请求怎么进来、怎么分到多个副本、多张卡怎么摆、集群怎么伸缩、出问题按什么顺序查。

性能指标的定义与瓶颈定位在 01-推理性能指标与瓶颈定位,调度与缓存的引擎机制在 03-推理调度:Continuous Batching 与 Chunked Prefill 与 04-前缀缓存:APC 与 RadixAttention。

LLM 服务为什么不是「Web 服务加个模型」 ​

传统模型服务(图像分类、推荐排序)是一次性的:一次前向、毫秒级返回、显存占用固定。LLM 服务在四个方面都不同:

差异后果
自回归生成长请求一次请求持续数秒到数十秒,GPU 在该请求存续期间一直被占 —— 资源占用的时间尺度完全不同
KV Cache 随请求动态增长显存占用是运行时的动态量,不能按静态峰值配(02-PagedAttention:KV Cache 的分页管理)
请求长度高度异质输入 10 token / 输出 500 token 与输入 2000 / 输出 20 都常见,批处理与排队策略必须能容纳这种方差
流式输出用户要逐字看到结果,需要 SSE 或 WebSocket;反过来这也意味着「总延迟」得拆成两段看:TTFT 加 TPOT(01-推理性能指标与瓶颈定位)

这四条决定了架构重心:请求时长的方差极大,所以负载均衡不能按连接数平均分;显存是动态的,所以容量规划要靠压测而非公式;延迟是两段式的,所以排队策略要能区分 Prefill 与 Decode。

典型四层架构 ​

客户端  Web / App / API
   │
   ▼
API Gateway      认证 · 限流 · 按模型名路由 · 请求响应日志
   │
   ▼
负载均衡器       最少连接 / 前缀感知 / 一致性哈希
   │
   ├────────────────┬────────────────┐
   ▼                ▼                ▼
推理节点 1        推理节点 2        推理节点 N
每节点一个引擎实例(vLLM 等),节点内可做 TP 分片
   │                │                │
   └────────────────┴────────────────┘
                    │
                    ▼
监控系统          Prometheus + Grafana
                  延迟 / 吞吐 / 队列 / 显存

负载均衡是四层里最容易被做错的一层。 LLM 请求的处理时长差异巨大(Decode 阶段可能比 Prefill 长几十倍),「轮询」会把新请求均匀甩给负载不同的副本 —— 应该用最少连接或最少在飞 token 数这类能反映实际负载的策略。

还能更进一步:前缀感知路由。 把命中同一 System Prompt 的请求导向同一副本,提高前缀缓存命中率。这一条是 04-前缀缓存:APC 与 RadixAttention 在集群层的延伸 —— 命中率不只取决于引擎,还取决于路由器把请求送到了哪。 代价是路由表要跟着副本的缓存状态走,副本重启后缓存失效需要感知。

路由策略:多模型服务 ​

同时提供 7B 与 70B 时(或不同能力的模型池),三种路由方式:

策略做法代价
按模型名客户端在请求里指定最简单;把复杂度判断推给了客户端
按请求复杂度轻量分类器先判复杂度,简单请求走小模型需要分类器,误判会掉质量
级联(Cascade)先让小模型答,置信度低再转大模型平均成本最低;置信度估计本身是难题

级联是「投机解码」在服务层的对应物 —— 用便宜的路走一遍,只在不确定时才付贵的代价(09-Speculative Decoding)。区别是投机解码有等价性保证,级联没有:小模型答错的题如果它自己很有信心,就直接漏过去了。

同一个入口下同时提供多种能力时,路由要回答两个独立的问题:用哪个模型,以及送到哪个副本。

一个请求进来,要回答两个独立的问题:用哪个模型,送到哪个副本

问题一:用哪个模型
├─ 客户端已经指定了模型名 ──▶ 按名路由
│      最简单,把「该用哪个模型」的判断推给了客户端
├─ 客户端只说要做这件事
│   ├─ 有轻量分类器判复杂度
│   │      ├─ 判为简单 ──▶ 小模型(误判就直接掉质量)
│   │      └─ 判为复杂 ──▶ 大模型
│   └─ 用级联(Cascade)
│          ├─ 小模型先答 ──▶ 置信度够高 ──▶ 返回(付便宜的代价)
│          └─ 置信度低 ────▶ 转大模型重答(付贵的代价)
│                 与投机解码的差别在等价性:级联没有保证,小模型答错
│                 而自己很有信心时就直接漏过去了
问题二:送到哪个副本
├─ 最少连接 / 最少在飞 token ──▶ 避免把新请求甩给负载已经很高的副本
└─ 前缀感知 ──▶ 命中同一 System Prompt 的请求导向同一副本
       代价:路由表要跟着副本的缓存状态走,副本重启后需要重新感知

弹性伸缩与冷启动 ​

负载有明显潮汐(工作日白天高峰、夜间低谷),按峰值常驻 GPU 是最大的浪费来源。

Kubernetes 下可以用 KEDA 按请求队列长度或 GPU 利用率做事件驱动扩缩 —— 注意扩缩容信号应该用队列深度而不是 QPS:QPS 是结果,队列深度才是「压不住」的直接征兆。

冷启动是这套方案的主要障碍:

模型规模权重体积(BF16)加载时间
7B14 GB数十秒
70B140 GB> 2 分钟(受存储带宽限制)

三个缓解手段:

  1. 预热池 —— 常驻少量空闲实例,用冗余换响应速度
  2. 权重本地缓存 —— 放在本地 NVMe 而不是每次从对象存储拉
  3. 分片并行加载 —— 用张量并行让多卡同时读各自的切片

K8s 探针要放宽,否则 Pod 活不到加载完

模型加载几分钟,默认的 readness/liveness 探针阈值会把 Pod 判死并重启 —— 重启后又要重新加载,进入死循环。探针的 initialDelaySeconds / failureThreshold 必须按模型加载时间设置,这也是 06-vLLM 部署、参数与服务特性 里那条运维经验的集群版本。

把冷启动接到弹性伸缩上,得到的是这样一条时序。注意扩缩容信号取队列深度,不取 QPS —— QPS 是结果,队列深度才是「压不住」的直接征兆。

多 GPU 与多节点 ​

单机内张量并行 ​

模型单卡放不下时用 TP 切到同节点的多张卡上(08-张量并行与序列并行):

bash
vllm serve meta-llama/Llama-2-70b-chat-hf \
    --tensor-parallel-size 4 \
    --max-model-len 4096 \
    --gpu-memory-utilization 0.9

TP 度数取 2 的幂(2/4/8),且尽量落在同一节点内 —— 因为 TP 每层都要 AllReduce,节点内 NVLink 与跨节点 InfiniBand 的延迟差着量级(03-集合通信与 NCCL)。

多实例优于跨节点模型并行 ​

有多台服务器时,每台跑独立实例 + 负载均衡比跨节点做模型并行更好:

部署模式GPU 配置承载模型并发能力
单卡1× A100/H1007B (BF16) 或 70B (INT4)低
节点内 TP2–8× GPU(NVLink)13B–70B (BF16)中
多实例 + 负载均衡N 台 × M 卡任意高,近线性扩展

理由是通信延迟的绝对量级:跨节点 MP 每一步都要走网络,而多实例方案里节点之间只在负载均衡层交互(无同步依赖)。把并行限制在节点内,是推理侧与训练侧的一个明确分野 —— 训练可以用跨节点 PP/DP,推理的实时性约束不允许。

混合部署:一张卡上放多个模型 ​

  • 同一基座 + 多个 LoRA —— vLLM 的 Multi-LoRA 支持在同一实例里热加载并逐请求切换适配器(16-参数高效微调:LoRA、QLoRA 与 Adapter 给出的正是这条服务侧价值)。比部署 N 个完整实例省得极多
  • 完全不同的模型 —— 靠 MIG(硬件分区,隔离强)或 Time-Slicing(时间片轮转,隔离弱但切分方式更自由)在物理 GPU 上切虚拟实例

Triton Inference Server 的位置 ​

Triton 不是推理引擎,是模型服务框架 —— 它管请求、版本、多模型与指标,不自己做 GPU kernel。

能力说明
多后端TensorRT、ONNX Runtime、PyTorch、vLLM、Python 自定义
动态 Batching自动合并请求为一个 batch
Model Repository文件系统上的模型版本管理,支持热更新
Ensemble把多个模型串成流水线(如 Tokenizer → LLM → Detokenizer)
指标暴露原生 Prometheus

LLM 场景下的典型组合是 Triton + TensorRT-LLM:TensorRT-LLM 负责引擎内的计算,Triton 负责引擎外的请求管理、版本控制与多模型编排。选它的理由是已经在用 TensorRT-LLM 且需要统一的模型管理面;如果只用 vLLM,vLLM 自带的 OpenAI 兼容服务通常就够了。

监控与告警 ​

指标与阈值 ​

类别指标告警示例
延迟P50/P95/P99 TTFT、TPOTP99 TTFT > 2 s
吞吐tokens/s(分输入/输出)、requests/s吞吐下降 > 30%
队列等待队列深度、排队时间队列深度 > 100
GPU利用率、显存占用、温度利用率 < 30% 或 > 95%
错误超时率、OOM 率、5xx 率错误率 > 1%

要分位数,不要平均值。 平均值会把「1% 的请求卡了 10 秒」这件事完全抹掉,而用户体验由那 1% 决定。

三个典型故障的排查路径 ​

TTFT 突然增大 → 看输入长度分布(Prefill 计算量)→ 看队列深度(并发过高)→ 看前缀缓存命中率(04-前缀缓存:APC 与 RadixAttention)。

GPU 利用率持续偏低 → 两可能:请求不够多(batch 撑不起来),或 Decode 阶段占比高(Decode 是访存密集,算力本就闲置 —— 见 01-推理性能指标与瓶颈定位 对 Prefill/Decode 两套瓶颈的区分)。后者不是故障,是负载形态。

OOM → 限制最大并发数 / 缩短 max-model-len / 启用 KV Cache 量化(08-量化)。单实例的参数级排错见 06-vLLM 部署、参数与服务特性。

三条排查线各有一套固定的观察顺序,走错顺序会花很多时间在错误的层上。

症状 1:TTFT 突然增大
├─ ① 看输入长度分布 ──── Prefill 的计算量涨了吗(提示词变长、RAG 召回变多)
├─ ② 看等待队列深度 ──── 并发超过单副本容量,涨上来的是排队时间
└─ ③ 看前缀缓存命中率 ── 命中率掉了,每个请求都在重算同一段 Prefill
       常见原因:请求被路由到没有这份缓存的副本,或 System Prompt 改过

症状 2:GPU 利用率持续偏低
├─ 请求不够多 ──── batch 撑不起来,瓶颈在并发数(该调并发,不是加卡)
└─ Decode 占比高 ── Decode 是访存密集,算力本来就闲置
       这不是故障,是负载形态;此时该看 TPOT,而不是继续盯利用率

症状 3:OOM
├─ 降最大并发数 ──── --max-num-seqs
├─ 缩短 max-model-len ─  KV 占用随上下文长度线性增长
└─ 开 KV Cache 量化 ── 显存占用直接砍半

成本优化 ​

手段收益前提
4-bit 量化权重显存降约 75%,同卡可服务更多请求质量能接受
选 GQA/MQA 模型KV Cache 降 4–8 倍模型本身支持(10-KV Cache 与推理优化)
前缀缓存省掉重复 PrefillSystem Prompt 固定(04-前缀缓存:APC 与 RadixAttention)
模型路由 / 级联简单请求不占大模型复杂度可判
弹性伸缩低谷释放 GPU冷启动可接受
Spot / 竞价实例GPU 单价降 50–70%只有对中断容错的批量任务适用

最后一行要额外注意:在线服务用竞价实例会在回收时直接掉请求,除非有跨区域冗余与请求迁移能力,否则省下的钱会被可用性损失吃掉。

本地与私有化部署 ​

三种不可外发数据的场景(企业敏感文档与代码、合规要求、离线环境)对应三档方案:

方案形态适用
llama.cpp + Ollama单机,一行命令起模型个人与小团队快速体验
vLLM 容器化企业内部 GPU 服务器有卡、要 OpenAI 兼容 API
K8s + GPU Operator多副本、滚更、弹性生产级私有部署

Apple Silicon 是本地部署的一条特殊路径:统一内存架构下 CPU 与 GPU 共享同一块内存,64 GB 的 M3 Max 能跑 70B 的 GGUF Q4 —— 这在 NVIDIA 侧至少要一块 A100 80GB。代价是带宽与算力代差,7B Q4 大约 15–30 tokens/s(07-端侧推理)。

决策表:

场景推荐关键考量
快速原型Ollama / vLLM 单机部署速度
中小规模在线服务vLLM + 负载均衡模型覆盖与生态成熟度
极致性能TensorRT-LLM + Triton编译代价与 NVIDIA 绑定
Agent / 结构化生成SGLang前缀缓存与格式约束
本地隐私vLLM 容器 / llama.cpp数据不出域、硬件条件
个人 MacOllama统一内存优势

相关 ​

参考 ​

该篇第 1 章的性能指标与本库 01-推理性能指标与瓶颈定位 重叠、第 7 章的端侧部署与 07-端侧推理 重叠、引擎对比已并入 06-vLLM 部署、参数与服务特性,本文只保留集群架构、路由、伸缩、Triton、监控与成本六块

贡献者 ​

文件历史 ​