生产级vLLM集群调度:AIBrix弹性路由与无损扩缩容实践
2026/9/14 13:34:29 网站建设 项目流程

把 vLLM 从单机部署挪到生产级多节点集群,是我去年踩过最深的一串坑。单机多卡跑一个模型,vLLM 自己把显存、队列、并发、KV Cache 都安排得明明白白;可一旦模型数量上到三五个、GPU 异构、流量带着明显潮汐,问题立刻变样:请求该进哪个实例、扩容该扩谁、某个 GPU 挂了流量怎么不感知地摘走,全得自己造轮子。NVIDIA 开源的 AIBrix 就是冲着这一层来的——它不是推理引擎,而是架在 vLLM 这类引擎之上的大模型弹性调度平台。这篇文章,是我基于源码逐模块阅读和实际压测后写的一份企业尽调报告,适合正在做 LLM 服务化架构选型、或者已经在用 vLLM 但被集群调度问题卡住的团队。后面也会穿插一些我看代码时标记出来的关键位置,方便你按同样路径去复查。

1. 为什么要把 AIBrix 单独拿出来看:单机 vLLM 掩盖的三个集群问题

1.1 问题一:模型多了之后,“流量该进哪个实例”没人管

单实例部署时,vLLM 起来之后监听一个端口,客户端直连这个端口,路由问题根本不存在。但生产环境不会只有一台虚拟机:同一个集群里可能同时跑着 chat 模型、embedding 模型、rag 用的 reranker,一个模型可能还有两个副本做容灾。这时候 K8s Service 只能做四层负载,把流量根据目标端口转发到后端 Pod,它区分不了 “/v1/chat/completions 应该去 chat 模型,而 /v1/embeddings 应该去 embedding 模型”。你只能在客户端自己拼好不同服务的地址,等于把路由逻辑散落到业务代码里。

更麻烦的是 KV Cache 的热度差异。同一个模型的两个副本,请求进来后分别占用了不同的前缀缓存;一个副本缓存了公共系统提示词,另一个没有。传统的四层负载不关心这些,只会机械地轮流转发。AIBrix 的做法是把“模型端点”作为路由粒度,数据面根据请求里的 model 参数和 URL 前缀做匹配,再通过调度策略落到具体 Pod。这个能力看起来不复杂,但它是后面所有弹性动作的入口——路由都不对,扩缩容扩得再准也没用。

1.2 问题二:弹性扩缩容的触发指标长期选错

很多团队从 Web 服务迁移到推理服务时,会把原来那套 CPU、内存监控直接搬过来。结果就是:请求排队已经涨到几百,CPU 还不到 20%,扩容永远慢半拍;反过来,深夜流量下来,显存已经被一个大模型实例占满,CPU 指标却始终很低,缩容策略根本不会触发。原因在于推理负载的特性完全不同:两个请求同时进来,一个问“1+1=?”一个问“请写一篇 5000 字的市场分析”,前一个几秒结束,后一个可能要跑几十秒,CPU 使用率差异很小,但排队和显存压力完全不是一个量级。

真正能反映推理实例压力的,是排队中的请求数、平均 decode 时延、KV Cache 水位以及单实例的吞吐上限。AIBrix 的 Scaler 按模型维度做弹性,而不是拿整个 Deployment 当黑盒去扩缩容;源码里能明显看到它对“推理指标”有单独抽象,而不是直接套用通用 HPA 那套指标接口。我在自己的集群里也验证过,用 KV Cache 占用和排队长度组合触发,比用 QPS 触发准很多,因为同样是一百个 QPS,长文档场景和短对话场景对资源的需求差了十倍不止。

1.3 问题三:单点故障与“无损摘流”

vLLM 默认走流式输出,也就是 SSE 长连接,用户已经开始读第一行答案了,后端还在慢慢生成后续内容。这时如果后端 Pod 因为节点维护、OOM、健康检查失败被 K8s 杀掉了,那个长连接会直接断开,用户看到的就是“回答到一半没了”。这个问题在单副本时代可以靠运维手动处理,多副本之后依然存在:你无法保证 K8s 的 readinessProbe 能在连接断开之前帮你把流量摘干净。

所以要真正“无感摘流”,必须由网关层感知后端状态:先把该实例从路由表剔除,不再分配新请求,然后等待已经在途的长连接结束或达到超时上限,最后才把 Pod 回收。AIBrix 的数据面把这类逻辑做成了内置能力,包括健康检查、动态权重和排空流程。我见过不少团队卡在这一步,最后只能给所有模型请求加超时,牺牲用户体验来换稳定性——这是可以在架构层面避免的。

2. 源码实证:仓库布局与四个核心组件的职责边界

2.1 先从目录结构建立整体地图

我把仓库克隆下来之后,没有直接钻进某个文件,而是先按 README 给出的架构文档过了一遍目录结构。给我的第一感觉是分层非常清楚:控制面相关逻辑在最上层,负责和 K8s API Server 打交道;数据面是独立的网关模块,负责处理真实流量;还有一块运行时组件,用来和 vLLM 集成。源码里大量出现 controller、planner、scaler、gateway 这些关键词,这几乎就是一份标准的 K8s controller 模式实现。

如果你也想从源码验证,建议按“控制面 → 数据面 → 运行时”的顺序读,先看每个模块的职责描述,再去看具体代码。不要一上来就纠结某个函数的实现细节,否则很容易被分布式调度中的各种并发分支带偏。另外可以顺手启动一个 vLLM 单实例,观察它的启动日志,比如出现 “pynccl.py” 里 “vllm is using nccl==2.30.7” 这类日志时,说明分布式通信已经初始化完成。搞清楚 vLLM 自身的启动和运行机制,再回来看 AIBrix 源码,会更容易理解哪些事情该由引擎管、哪些事情该由调度平台管。

2.2 Controller 与自定义资源:把“模型”变成 K8s 对象

Controller 是整个控制面的核心入口。AIBrix 没有把模型、路由规则、弹性策略写死在配置里,而是扩展了 K8s 的 CRD 机制,把“模型”“模型端点池”“路由别名”“伸缩策略”这类概念都表达成自定义资源对象。你在控制面创建了一个模型对象之后,Controller 会监听这个对象的变化,自动去调和底层 Deployment、Service、Pod 的状态,把实际状态拉向期望状态。

这种设计真正的价值是声明式管理。手写脚本管理推理集群是命令式的:先创建 Deployment,再创建 Service,再配置路由,哪一步执行到一半失败,整个状态就乱了,而且事后很难排查。有了 Controller 之后,你只需要声明“我要跑这几个模型,每个模型最多多少副本、最少多少副本”,剩下的由控制循环去保证。这对企业运维很重要,因为任何故障恢复都可以通过重新应用 YAML 来完成,而不是靠人去敲一串不可复现的命令。

2.3 Planner:路由策略的翻译器

Planner 是 AIBrix 调度语义的大脑,负责在做路由决策时选择具体后端实例。它保留了最基础的随机和轮询策略,也提供了几类更“懂推理”的策略。一类是 KVCache-aware,它能看到每个后端实例当前缓存了哪些前缀,尽量把带有相同系统提示词或用户前缀的请求路由到已经缓存了这段 KV 的实例上,从而省掉重复的 prefill 计算。另一类是 Reputation-based,给后端实例打一个包含成功率、平均延迟和健康状态的综合分,分数低的实例会被降低权重,这在节点出现隐性故障时很有用。

源码里这些策略是可插拔的,不是一个巨大的 if-else。这也意味着企业可以根据自己的负载特征扩展策略。我在实测里发现,如果业务有大量公共系统提示词和 few-shot 前缀,KVCache-aware 路由的收益会非常明显;但如果每个请求的前缀几乎都不一样,这个策略带来的额外计算成本很可能高于收益。选策略之前,最好先统计一下线上请求的前缀重复率。

2.4 Scaler:按模型维度做水平伸缩

Scaler 和通用 HPA 最大的区别在于伸缩粒度。HPA 针对的是一个 Deployment,触发一次扩容会把整个 Deployment 的副本数调大;而 AIBrix 的 Scaler 看到的是模型对象,可以给同一个集群里的不同模型设置完全不同的伸缩策略,互不干扰。它在实现上还带了冷却窗口、最小最大副本限制和排空逻辑,避免因为瞬时抖动把副本数拉起又立刻缩掉。

这部分源码值得仔细看,因为它把“推理场景下什么才算真实负载”体现得很清楚。它采集的是每个模型的请求速率、排队情况、KV Cache 使用率这类数据,而不是简单的 CPU、内存。对做企业的团队来说,这一层可以直接决定你的 GPU 成本是跟着业务真实需求走,还是被不合理的扩缩容白白烧掉。

2.5 Gateway:数据面的 Envoy 扩展

数据面是真正承接用户流量的部分。AIBrix 的 Gateway 基于 Envoy 做了扩展,实现了前缀路由、模型别名匹配、权重分配、限流、重试以及后端摘流等能力。它和控制面分离,这一点非常关键:即使控制面短暂不可用,数据面仍然可以按照最后一份有效的路由策略继续转发请求,不会出现“调度平台挂了,推理服务全挂”的连锁故障。

用 Envoy 做底座的好处是生态成熟,企业里通常已经有 Envoy 运维经验;坏处是排查问题时要同时理解两层问题——是 Envoy 本身的流量处理,还是 AIBrix 自定义 filter 的逻辑。这一点我会在后面风险清单里再展开。

3. 弹性调度的完整决策链路:从指标采集到请求落点

3.1 采集哪些指标,怎么反馈给控制面

弹性调度闭环的第一步是指标采集。AIBrix 的运行时组件会从 vLLM 暴露的指标端口拉取模型级状态,比如当前排队请求数、生成速率、KV Cache 占用和延迟分布。控制面的 Scaler 周期性地拉取这些指标,计算当前负载和目标负载的比值,从而决定是否需要调整副本数。

计算思路可以简化理解为:期望副本数等于当前副本数乘以当前负载与目标负载的比值,同时受最小最大副本数约束。但实际生产里绝对不能只做一个比例换算,因为瞬时波动会让副本数量来回抖动,所以必须加冷却窗口和缓冲。我自己的经验是:先给每个模型标定单副本能够承受的最大排队深度,再设置一个保守的目标水位,例如排队请求数超过 32 就触发扩容,排队持续 5 分钟为空才缩容。用 “vllm bench serve” 这类压测工具把单实例的吞吐上限打出来之后,这些数字会更有依据。

3.2 一次请求经 Gateway 的完整旅程

把控制面、数据面、运行时串起来看,一次请求的完整路径大致是这样:

  1. 客户端把请求发到 Gateway,路径里带模型标识,或者是 body 参数里的 model 字段。
  2. Gateway 解析请求,匹配到对应的模型端点和路由别名。
  3. 根据 Planner 选择的策略,从可用后端实例里挑出一个目标 Pod。
  4. Gateway 把请求转发给该 Pod,保留 SSE 流式语义,确保用户可以持续收到生成内容。
  5. 如果后端返回错误或连接超时,Gateway 会根据重试策略换一个后端重试;生成类请求重试要格外谨慎,盲目重试会导致重复计费和重复输出。
  6. 请求结束后,数据面记录这次调用的延迟、成功率和 token 数,供后续调度和监控使用。

这个链路里最重要的是第 3 步和第 5 步。第 3 步决定了你的调度策略是否真的生效,第 5 步决定了故障时用户体验能不能保住。很多团队在自研方案里把这两步混在了一起,结果要么调度策略不灵活,要么故障恢复很粗暴。

3.3 落地时最容易抖的三类场景与对策

第一类是短突发:业务方一次错误操作导致客户端瞬间重试,QPS 翻了十倍。如果直接按瞬时负载扩容,副本数会飙升然后雪崩。对策是给模型设置最小副本数兜底,同时在 Gateway 层做好限流,把突发流量挡在系统能承受的范围内。

第二类是模型“变胖”:vLLM 加载一个大模型时,显存占用会非常高,滚动扩容期间节点可能瞬间被打满。对策是扩容前先做预热,让新 Pod 加载好权重、完成健康检查之后再加入路由;同时把扩缩容冷却时间拉长,避免反复横跳。

第三类是缩容杀错实例:缩容时选了正在跑长流式请求的 Pod,导致连接中断。对策是缩容前先触发摘流,把实例从路由表里剔除,等待在途连接自然结束或超过排空上限后,再执行回收。

3.4 一个小压测方法:用 vllm bench serve 标定单实例容量

我建议团队在配置 Scaler 之前,先用 vllm bench serve 或者自己写一个并发脚本,对不同输入长度和输出长度组合做一轮压测。记录每个组合下单实例的最大并发、P50/P95 延迟和 KV Cache 峰值。拿到这组数据之后,再回过去设置弹性阈值,就不会全靠拍脑袋。

4. 与 vLLM 的集成:Runtime 侧做了什么,边界在哪里

4.1 vLLM 的扩展点:指标、健康检查与控制指令

AIBrix 和 vLLM 的集成点主要发生在运行时模块。它并没有去修改 vLLM 的推理内核,而是作为伴随组件,从 vLLM 暴露的指标端点读取每个模型的状态,再把这些状态上报给控制面。vLLM 本身自带 OpenAI 兼容接口和 metrics 端点,AIBrix 利用的是这些现成出口,而不是自己重新发明一套协议。

理解这一点很重要,因为很多人会误以为引入 AIBrix 就要动 vLLM 的底层能力。实际上 vLLM 的核心优化——PagedAttention 把 KV Cache 按页管理、Continuous Batching 动态组合请求、分布式 tensor parallelism 等——都发生在引擎内部,调度平台管不到也不需要管。如果再往深说一层,Transformer 架构的注意力计算天然需要把历史 token 的 KV 缓存下来,这就是 KV Cache 的由来,也是调度时能不能命中缓存的关键。AIBrix 管的只是“请求放到哪个实例上最优”“实例数量该是多少”“故障时流量怎么摘”这三件事。边界划清楚之后,出问题时排查范围会小很多。

另外注意,如果模型是 MoE 架构,“显存占用高”不一定等于“计算繁忙”,因为 MoE 的激活参数分散在多个 expert 上,调度平台只要保证副本数和路由正确,真正对 MoE 做专家并行层面的优化还是引擎的事。这一点在做容量评估时容易看走眼。

4.2 和多引擎(SGLang)放一起怎么选

线上不少团队会拿 SGLang 和 vLLM 做对比。SGLang 的 RadixAttention 在共享前缀场景下确实能省很多 prefill 计算,如果业务特征是大量重复的 system prompt 或者长文档前缀,SGLang 可能更占优。但 vLLM 的社区生态更广,企业实践案例更多,AIBrix 对其支持也最完整。

我的建议是先把推理引擎定下来,再判断要不要上 AIBrix。不要为了用调度平台去换底层引擎,那会把问题扩大两倍——既要处理引擎差异带来的行为变化,又要处理调度平台本身的运维问题。如果团队已经有多套引擎并存,可以先在 Gateway 层统一入口,再逐步评估哪种引擎的负载适合纳入 AIBrix 的统一调度。

4.3 部署 AIBrix 的推荐拓扑与网络注意点

从生产部署的角度,我建议控制面组件放在 CPU 节点,Gateway 作为集群入口单独部署并通过负载均衡暴露,GPU 节点只跑推理 Pod。这样控制面被异常流量打爆时,不会拖垮推理进程;GPU 节点重启也不会影响控制面稳定性。

网络规划上,Gateway 到后端 Pod 之间建议走集群内网直连,指标端口只对控制面开放,不要直接暴露到公网。如果集群里同时跑多个 vLLM 实例且模型较大,还要关注节点间 NCCL 通信的带宽,因为这会影响分布式推理的扩展效率。AIBrix 在逻辑调度之上不会替你解决物理网络瓶颈,它只能帮你把流量分到更合理的节点,前提是节点本身通信正常。

5. 企业尽调结论:AIBrix 适合谁、何时上、怎么避坑

5.1 三个值得上的典型场景

并不是所有团队都应该立刻上 AIBrix,但从企业落地角度看,有三类场景它的价值非常明确:

场景核心痛点AIBrix 价值落地难度
多模型共享 GPU 池流量进错实例、资源利用率低按模型粒度路由与伸缩
模型多版本灰度发布新版本不敢直接切换别名路由与权重调整中高
流量潮汐明显扩容慢、空闲时 GPU 浪费自动扩缩容与排空

第一类场景最常见:几个业务线共用一批 GPU,谁要用模型谁就来申请资源,最后变成人为排期。AIBrix 把资源池化和模型级调度结合起来之后,不需要人为干预,都能在池子里找到位置。第二类场景适合做模型迭代快的团队,新版本先用小流量验证,确认稳定后再逐步提高权重。第三类场景适合业务高峰和低谷差异明显的团队,夜间流量低谷自动缩容,能省下不少 GPU 成本。

5.2 哪两类团队先别上

第一类是只跑一个模型、流量长期平稳的团队。这种场景下 AIBrix 带来的收益非常有限,反而增加了一个控制面和一层网关,等于多出了一个故障域。第二类是 K8s 运维基础还比较薄弱的团队,如果监控告警都没闭环,直接上调度平台,出了问题会很难定位是模型问题、网关问题还是控制面问题。

另外,如果业务对 GPU 显存隔离有非常强的合规要求,比如多租户之间不允许任何显存越界风险,那么 AIBrix 这种逻辑层调度还不够,还需要配合 MIG、时间片或独立物理节点来强化隔离。调度平台负责的是“怎么把流量分配得更合理”,不是“怎么把显存物理切开”。

5.3 技术风险清单

按照我从源码和现场压测得到的经验,企业在 PoC 阶段就应该重点检查这几个风险点:

  • 版本耦合:vLLM 上游迭代非常快,一旦指标接口或启动参数变化,AIBrix 运行时可能失效。需要固定 vLLM 版本,并在升级前做回归测试。
  • 控制面高可用:Controller、Scaler 如果只部署单副本,调度器本身会成为新的单点。至少要双副本,并配置好 leader 选举。
  • 网关性能损耗:引入 Envoy 网关意味着多一跳 L7 转发,压测时必须给网关预留独立资源,不能把网关和推理容器挤在一起。
  • 重试语义:LLM 生成类接口不能像普通 HTTP 接口一样随意自动重试,重复请求会带来重复输出和计费问题。重试策略要按接口语义细化。
  • 安全暴露面:网关作为统一入口,集成了鉴权、限流、审计等能力后会扩大攻击面,必须做严格的访问控制和日志留存。

5.4 我的落地建议:分三阶段推进

如果你想上 AIBrix,我的建议是不要一次把所有能力都打开,而是分三步走。第一阶段,只上 Gateway 和路由能力,把多模型入口统一起来,自动伸缩先关掉。这个阶段的目标是拿到统一的流量入口和可观测性。第二阶段,接入模型级指标,打开 Scaler,但先用保守阈值,比如排队深度超过上限再扩,排空持续很久才缩,把抖动压到最低。第三阶段,再引入金丝雀发布、多策略路由和容量模型,这时候你已经有了前两个阶段积累的数据,调参就不是拍脑袋了。

压测配置方面,建议先用 vllm bench serve 类工具把每个模型的基准吞吐打出来,再结合真实的排队长度和 KV Cache 水位设置阈值。这里有一个我踩过几次坑之后总结出来的小技巧:判断扩容不要只看 QPS,而是看“排队中的请求数 + KV Cache 水位”这两个维度;QPS 高但每个请求很短的时候,实例其实挺得住,过早扩容反而浪费。

最后说一点个人体会。AIBrix 不是让单台机器把模型跑得更快,而是让整个推理集群在业务压力下不散架。它省下的是“自己维护调度器”的长期成本,代价是学习和运维曲线确实比裸部署 vLLM 要陡。用不用,取决于你当下有没有这类跨实例、跨模型的问题;如果还没有,先把单机性能吃透,反而更划算。选型时可以把源码里那几条可插拔策略当作需求清单,对照自己的真实流量特征再动手,而不是先上平台再找场景。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询