AIBrix Router 架构与路由算法实战:可插拔的 LLM 推理流量调度引擎
2026/9/18 18:38:23 网站建设 项目流程

AIBrix Router 架构与路由算法实战:可插拔的 LLM 推理流量调度引擎

【免费下载链接】aibrixCost-efficient and pluggable Infrastructure components for GenAI inference项目地址: https://gitcode.com/GitHub_Trending/ai/aibrix

导读

AIBrix Router 是 AIBrix LLM 推理服务栈中负责智能流量管理的核心组件,它以 Envoy Gateway 外部处理(External Processing)扩展的形式嵌入网关,作为所有 LLM 推理请求的唯一入口,屏蔽了多模型、LoRA 适配器、异构 GPU 后端与多样化扩缩容策略的底层复杂性。本文以 AIBrix Router 设计文档 为主干,结合 网关路由功能指南、生产部署指南 以及 pkg/plugins/gateway 下的源码实现,系统讲解路由器的核心原理、内置路由策略、配置方式与算法扩展方法。读完本文,你将掌握如何在 AIBrix 中按流量特征选择路由策略、通过请求头与环境变量精细控制路由行为,并能够基于Router接口开发自定义路由算法。

核心设计原则:本地缓存 + 多目标路由

AIBrix Router 与"每次请求实时查询 Pod"的朴素路由方案不同,它通过周期性拉取与订阅机制维护一份高频更新的 Pod 指标本地缓存(涵盖 pod 运行中请求数、KV cache 占用、drain rate 等),所有路由算法基于这份缓存快照做决策,而不阻塞地实时查询各 Pod。这一设计带来了两个关键收益:

  • 热路径低延迟:路由决策只做内存内的指标读取与打分计算,不需要在请求关键路径上发起网络查询;
  • 高 QPS 扩展性:缓存由独立组件持续刷新,网关可以轻松支撑数千 QPS 的推理流量(设计文档中明确以 "scaling to thousands of QPS" 为设计目标)。

路由策略的选择有三层优先级(从高到低):

  1. 每请求通过routing-strategyHTTP 请求头指定;
  2. 通过ROUTING_ALGORITHM环境变量全局指定默认策略;
  3. 通过模型配置档案(model config profile)注解为特定模型指定策略。

这条策略解析链在源码中有完整实现:RouterManager.Select(pkg/plugins/gateway/algorithms/router.go)先解析算法字符串,再按配置选取路由器实例;Validate()则在请求进入前校验策略名是否被注册,未注册的策略会返回 400 Bad Request,而不是静默回退到 random。

详细请求序列流程

设计文档给出了完整的请求流转时序,我们将其整理并补充实现佐证:

Client │ │ POST /v1/chat/completions ▼ Envoy │ │ External Processing Hook ▼ GatewayPlugin │ │ Make routing decision ▼ Router ──────────────────▶ Cache │ Query pod metrics │ │ & KV state │ │ ◀─────────────────────────┘ │ Return latest metrics │ │ Apply routing algorithm │ │ Forward request to selected pod ▼ InferencePod │ │ Return streamed tokens ▼ GatewayPlugin ──▶ Envoy ──▶ Client

对应到源码:请求经 Envoy 的 ext_proc 过滤器转发给 gateway plugin(pkg/plugins/gateway/gateway.go),selectTargetPod负责解析策略、应用负载不均衡门控(ApplyLoadImbalanceGate)、随后调用路由器选出目标 Pod;RoutingContext.TargetAddress()(pkg/types/router_context.go)最终拼出IP:Port地址,供 Envoy 将请求转发到选中的推理 Pod。流式 token 沿反方向经 Envoy 回传客户端。

内置路由策略全解析

AIBRIX 提供了一套面向不同工作负载特征的内置算法,全部注册于 pkg/plugins/gateway/algorithms 目录下的init()函数中。以下按设计文档的分类逐一说明。

通用负载均衡(General Load Balancing)

策略名行为描述源码文件
random随机选择一个 Pod,适合作为基线或 Pod 同构、负载均匀的场景random.go
least-request选择在途请求数最少的 Podleast_request.go
least-busy-time选择累计忙碌处理时间最短的 Podleast_busy_time.go
least-latency选择平均处理延迟最低的 Podleast_latency.go
least-kv-cache选择当前 KV cache 占用(VRAM 用量)最小的 Podleast_kv_cache.go
least-gpu-cache选择 GPU cache 利用率最低的 Podleast_gpu_cache.go
least-utilization选择整体利用率评分最低的 Podleast_util.go
load-balance容量感知的加权 least-request 路由,见下文详解load_balance.go
throughput选择累计处理加权 token 数最少的 Pod,偏向负载较轻的 Podthroughput.go
power-of-two两随机选择(power-of-two choices)算法:随机采样两个 Pod 并选择更优者power_of_two.go

load-balance的容量感知打分:每个 Pod 的评分定义为running_requests / drain_rate(即预计排队时间 pending time),其中drain_rate是观测到的请求完成速率。路由选择 pending time 最低的 Pod;当多个 Pod 平局时,用"最小 GPU+CPU 组合 KV-cache 用量"作为次级信号破平(若平局 Pod 的缓存指标不可用则随机选择)——这与prefix-cache用请求数来打破前缀匹配百分比平局的模式一致。当 drain-rate 指标不可用时,回退到均匀容量(drain_rate = 1)假设。实现细节见 load_balance.go。

KV-Cache 感知(KV-Cache Aware)

  • prefix-cache:路由到已缓存与该请求 prompt 前缀匹配的 KV cache 的 Pod,在标准差负载阈值(AIBRIX_PREFIX_CACHE_STANDARD_DEVIATION_FACTOR,默认 1)内选择前缀匹配最佳者。它纯粹关注前缀缓存命中率,自身不执行集群级负载不均衡门控(该门控由网关在路由前统一施加,见下文"负载不均衡门控"小节)。支持两种模式:
    • 标准模式:本地哈希表索引;
    • KV 同步模式:通过实时分布式索引共享跨副本的 KV 状态,需设置AIBRIX_PREFIX_CACHE_KV_EVENT_SYNC_ENABLED=true,同时要求AIBRIX_PREFIX_CACHE_USE_REMOTE_TOKENIZER=trueAIBRIX_PREFIX_CACHE_TOKENIZER_TYPE=remote。完整依赖关系见 pkg/plugins/gateway/ENV_VARS.md。
  • prefix-cache-preble:同时考虑前缀缓存命中率与 Pod 负载,基于 Preble 论文(Efficient Distributed Prompt Scheduling for LLM Serving)的思想实现,见 prefix_cache_preble.go。

公平性(Fairness)

  • vtc-basic:用混合评分平衡"每用户 token 公平性"与"Pod 利用率",是 Virtual Token Counter(VTC)算法的简化变体,实现在 pkg/plugins/gateway/algorithms/vtc 目录。其评分公式为score = (fairnessWeight * normFairness + utilizationWeight * normUtilization) / normFreeGPU,相关权重(如AIBRIX_ROUTER_VTC_BASIC_FAIRNESS_WEIGHTAIBRIX_ROUTER_VTC_BASIC_UTILIZATION_WEIGHT,均默认 1.0)与输入/输出 token 权重(默认 1.0 / 2.0)均可用环境变量调优。

SLO 感知(SLO-Aware)

策略名行为描述
slo感知每请求服务等级目标(SLO)的路由
slo-pack-loadSLO 感知且把负载打包到更少 Pod 上以提升效率
slo-least-loadSLO 感知且把负载分散到最空闲的 Pod
slo-least-load-pullingslo-least-load的变体,直接拉取实时指标而非依赖缓存快照

实现位于 slo.go 与 pkg/plugins/gateway/queue 目录。

专用策略(Specialized)

  • pd:prefill-decode 分离路由,将处理拆分为专用 prefill Pod 与 decode Pod,以优化端到端延迟。实现分散在 pd_disaggregation.go 与 pkg/plugins/gateway/algorithms/pd 子目录,支持通过AIBRIX_PROMPT_LENGTH_BUCKETING按 prompt 长度分桶、通过AIBRIX_PREFILL_SCORE_POLICY/AIBRIX_DECODE_SCORE_POLICY分别选择 prefill/decode 打分策略。
  • session-affinity:粘性会话路由。将目标 Pod 地址(IP:Port)base64 编码进x-session-id响应头;后续携带该头的请求被路由到同一 Pod;若原 Pod 不可用,则回退到随机可用 Pod 并签发新的 session ID。注意x-session-id只编码网络位置,不是安全令牌,不能用于认证或授权。实现见 simple_session_affinity.go。

自动混合容量感知(Auto-Blended Capacity Awareness)

这是设计文档强调的一个"默认开启、无需 opt-in"的能力:除专属策略(pdslo/slo-*)和显式单独选择load-balance之外,其余每个策略在后台都会静默混入load-balance的容量感知打分;当所选策略本身不按请求数路由时,还会额外混入least-request(以保持多端口 / 数据并行 Pod 路由在混合打分下仍能工作)。调用方对此无感知——ctx.Algorithm、响应头与Validate()仍然只反映用户实际请求的策略名。这使得任何单一策略都无法在负载不均衡门控之外,把流量持续引向已经过热的 Pod。

该机制的核心实现在appendLoadBalanceBlend(router.go):它对算法字符串做解析、附加load-balance:N(以及需要的least-request:N)后,走multiStrategyRouter的软打分(soft-scoring)管道。多策略路由的每个子策略先产出原始分,经 winsorize 裁剪(MAD 稳健化、剔除极端离群值)与 min-max 归一化后按权重系数加权求和,取最高分 Pod 为胜者(scoreAndRank)。

可用环境变量控制:

  • AIBRIX_ROUTING_AUTO_BLEND_LOAD_BALANCE_WEIGHT(默认1):混入的load-balance打分权重,设为0可整体关闭自动混合功能;
  • AIBRIX_ROUTING_AUTO_BLEND_LEAST_REQUEST_WEIGHT(默认1):混入的least-request打分权重,设为0则从混合中剔除该项。

负载不均衡门控(Load-Imbalance Gate)

与自动混合互补的是中央负载不均衡门控:网关在selectTargetPod中、对最终生效的任意路由策略执行之前,统一调用ApplyLoadImbalanceGate(gateway.go),把候选 Pod 收窄到负载最低的子集。触发条件由两个环境变量控制:

  • AIBRIX_LOAD_BALANCE_IMBALANCE_FACTOR(默认2.0):3 个及以上 Pod 时,当max_req > factor × (mean_req + 1)触发门控;
  • AIBRIX_LOAD_BALANCE_IMBALANCE_MIN_GAP(默认8):要求max_req − min_req的绝对差值至少为 8 才触发。

专属策略(pdslo*)豁免此门控,因为它们自行管理各自的 Pod 子集。设计文档明确强调:该门控不是load-balance专属,而是对包括prefix-cacheprefix-cache-preble在内的所有非专属策略统一生效。详见 pkg/plugins/gateway/ENV_VARS.md。

如何扩展路由算法

路由框架是高度可插拔的,所有路由逻辑都通过Router接口表达(定义在 pkg/types/router.go):

// Router defines the interface for routing logic to select target pods. type Router interface { // Route selects a target pod from the provided list of pods. // The input pods is guaranteed to be non-empty and contain only routable pods. Route(ctx *RoutingContext, readyPodList PodList) (string, error) }

参数说明

  • ctx *RoutingContext:每请求的上下文,携带路由输入。关键字段(见 pkg/types/router_context.go):
    • Algorithm—— 当前生效的路由策略名;
    • Model—— 从请求体中提取的模型名;
    • Message—— 原始 prompt 文本(可用于 token 级决策);
    • User—— 可选用户标识(公平性类算法使用);
    • ReqHeaders—— 入站 HTTP 请求头的副本;
    • ConfigProfile—— 已解析的模型配置档案(策略覆盖、RPS 限制等),未设置时为nil
    • 另有BaseModel(LoRA 请求的基座模型名)、Stream(是否流式)、RequestIDReqPath等字段可供算法读取。
  • readyPodList PodList:预过滤后的健康且可路由的 Pod 列表,保证非空。

返回值:选中 Pod 的IP:Port字符串(如"10.0.0.5:8080");选择失败时返回非 nil error。

新增一个算法(4 步)

  1. 在 pkg/plugins/gateway/algorithms 目录新建*.go文件并实现Router接口;
  2. 声明策略名的类型化常量:
const RouterMyStrategy types.RoutingAlgorithm = "my-strategy"
  1. init()中注册构造函数,使其在启动时被框架拾取:
func init() { Register(RouterMyStrategy, NewMyStrategyRouter) }
  1. 通过routing-strategy请求头按请求指定,或设置ROUTING_ALGORITHM=my-strategy作为全局默认。

RouterManager提供了Register/RegisterProvider/Validate/Select/Init/SetFallback等完整的管理原语(router.go),其中Validate负责校验策略名是否已注册,Select负责构造路由器实例。

可选能力接口(同样定义于 pkg/types/router.go):

  • QueueRouter—— 为内部维护队列、暴露队列长度的路由器提供支持(Len() int);
  • FallbackRouter—— 通过委托给次级路由器实现链式路由,当主路由器无法决策时启用回退(SetFallback(RoutingAlgorithm, RouterProviderFunc));
  • PodScorer—— 实现批量软打分的策略可进一步参与多策略混合路由(ScoreAll+Polarity),这是上文自动混合机制能够工作的前提。

路由策略的三种配置途径

方式一:每请求通过routing-strategy请求头

curl -v http://${ENDPOINT}/v1/chat/completions \ -H "routing-strategy: least-request" \ -H "Content-Type: application/json" \ -d '{ "model": "your-model-name", "messages": [{"role": "user", "content": "Say this is a test!"}], "temperature": 0.7 }'

方式二:全局默认通过ROUTING_ALGORITHM环境变量

在 gateway plugin 部署中设置ROUTING_ALGORITHM=prefix-cache即可让所有未显式指定策略的请求默认走该策略。该环境变量在 pkg/plugins/gateway/types.go 与 util.go 中被读取。

方式三:通过模型配置档案(Config Profile)按模型指定

配置档案把路由设置直接嵌入模型 Pod 的注解,使发往该模型的每个请求自动获得正确配置,且可在注解内定义多个命名档案、用单个请求头在档案间切换。在DeploymentStormServiceRayClusterFleet的 Pod 模板上添加model.aibrix.ai/config注解:

annotations: model.aibrix.ai/config: | { "defaultProfile": "default", "profiles": { "default": { "routingStrategy": "least-request", "requestsPerSecond": 200 }, "large-input": { "routingStrategy": "pd", "routingConfig": { "promptLenBucketMinLength": 8192, "promptTokensGte": 8192, "prefillScorePolicy": "prefix_cache", "decodeScorePolicy": "load_balancing" }, "requestsPerSecond": 50 }, "cache-friendly": { "routingStrategy": "least-kv-cache", "requestsPerSecond": 150 }, "offline-generation": { "routingStrategy": "throughput", "routingConfig": { "maxTokensGte": 2048 } } } }

顶层字段

字段说明
lockedRoutingStrategy在模型级别锁定唯一路由策略。设置后优先级高于routing-strategy请求头、档案内routingStrategyROUTING_ALGORITHM环境变量;其余档案级旋钮(requestsPerSecondroutingConfig)仍按config-profile选中的档案生效
defaultProfile未发送config-profile请求头时使用的档案名,缺省回退到"default"
profiles命名档案的映射,每个档案包含下述字段

档案字段

字段说明
routingStrategy该档案的路由算法(如least-latencyprefix-cachepd
requestsPerSecond该档案的模型级 RPS 上限,超限请求以 HTTP 429 拒绝;省略或设为0表示不限
routingConfig算法专属设置的嵌套 JSON 对象。config-profile: auto时还从中读取请求级选择提示

请求时选择档案

# 使用 "batch" 档案处理该请求 curl http://${ENDPOINT}/v1/chat/completions \ -H "config-profile: batch" \ -H "Content-Type: application/json" \ -d '{"model": "my-model", "messages": [{"role": "user", "content": "Summarize..."}]}'
# 让网关依据 routingConfig 中的提示自动解析具体档案 curl http://${ENDPOINT}/v1/chat/completions \ -H "config-profile: auto" \ -H "Content-Type: application/json" \ -d '{"model": "my-model", "messages": [{"role": "user", "content": "Summarize..."}], "max_tokens": 4096}'

config-profile: auto时,网关评估每个档案routingConfig中支持的请求级提示(当前支持promptTokensGtepromptTokensLtmaxTokensGtemaxTokensLt),仅当档案的全部提示都与请求匹配时才命中;若无档案匹配则使用defaultProfile(或"default")。promptTokens*使用网关已有的 prompt 文本提取与本地 token 估算,maxTokens*优先读max_tokens,缺失时读max_completion_tokens

路由策略优先级(从高到低):

  1. lockedRoutingStrategy(模型级锁定,始终最高,甚至压过routing-strategy请求头);
  2. routing-strategy请求头;
  3. 解析后档案的routingStrategy(由config-profile头、config-profile: auto的 routingConfig 提示或defaultProfile解析而来);
  4. ROUTING_ALGORITHM环境变量。

向后兼容:若 Pod 没有model.aibrix.ai/config注解,网关直接回退到routing-strategy请求头与ROUTING_ALGORITHM环境变量,存量部署无需迁移。配置档案的解析与校验实现在 pkg/plugins/gateway/configprofiles。

按工作负载特征选择策略

生产部署指南给出了按流量模式选型的建议(详见 docs/source/production/gateway.rst):

  • 多轮对话 / prompt 前缀重叠高的负载 —— 用prefix-cache:当请求共享公共前缀(系统提示词、few-shot 示例、对话历史)时,prefix-cache把请求路由到已在 GPU 内存中持有匹配 KV-cache 块的 Pod,减少冗余计算并改善延迟。算法内部细节与配置项见 prefix_cache_readme.md。
  • 彼此独立、无前缀重叠的请求 —— 用least-request:每个请求 prompt 唯一、无 KV-cache 复用收益时,least-request总是路由到在途请求最少的 Pod,实现均匀分布。
  • 高吞吐且需要计算分离 —— 用pd:prefill-decode 分离把 LLM 推理的两个阶段拆到专用 Pod 上,两者可独立定容与扩缩容,在高请求量下提升 GPU 利用率。部署要求与配置见 pd_readme.md。

需要强调的是:若请求未携带routing-strategy头,网关默认使用random路由random适合测试与低流量场景,任何生产部署都应显式设置routing-strategy,避免依赖默认行为。

关键环境变量速查

路由相关核心环境变量汇总(完整清单见 pkg/plugins/gateway/ENV_VARS.md):

变量默认值说明
ROUTING_ALGORITHM默认路由算法(无每请求覆盖时生效)
AIBRIX_ROUTING_AUTO_BLEND_LOAD_BALANCE_WEIGHT1自动混合中load-balance打分权重;0关闭整个自动混合
AIBRIX_ROUTING_AUTO_BLEND_LEAST_REQUEST_WEIGHT1自动混合中least-request打分权重;0从混合中剔除
AIBRIX_LOAD_BALANCE_IMBALANCE_FACTOR2.0负载不均衡门控的倍数阈值(3+ Pod)
AIBRIX_LOAD_BALANCE_IMBALANCE_MIN_GAP8负载不均衡门控的最小绝对差值
AIBRIX_PREFIX_CACHE_TOKENIZER_TYPEcharacter前缀缓存哈希的 tokenizer 类型:charactertiktokenremote
AIBRIX_PREFIX_CACHE_STANDARD_DEVIATION_FACTOR1前缀匹配 Pod 的负载标准差阈值因子
AIBRIX_PREFIX_CACHE_KV_EVENT_SYNC_ENABLEDfalse是否启用跨网关副本的 KV 事件同步(需配合 remote tokenizer)
AIBRIX_PROMPT_LENGTH_BUCKETINGfalse是否按 prompt 长度分桶路由到 prefill Pod
AIBRIX_PREFILL_SCORE_POLICYprefix_cacheprefill Pod 选择策略:prefix_cacheleast_request
AIBRIX_DECODE_SCORE_POLICYload_balancingdecode Pod 选择策略:load_balancingleast_request
AIBRIX_STATESYNC_ENABLEDfalse启用 Redis 支撑的跨副本状态增量同步(多副本prefix-cache路由一致性的前提)
PROMETHEUS_ENDPOINTPrometheus HTTP API 地址;为空则跳过 PromQL 类指标查询

注意:依赖 PromQL 指标的策略(如least-latencyleast-kv-cache等)需要正确配置PROMETHEUS_ENDPOINT以及可选的 Basic Auth 凭据(支持环境变量明文或 Kubernetes Secret 两种方式,后者优先)。

多副本部署注意事项

当 gateway plugin 副本数超过 1 时,需要满足两个条件才能保证路由决策一致(详见 docs/source/production/gateway.rst):

  1. 连接 Redis:gateway plugin 启动时读取REDIS_HOST环境变量;若未设置或 Redis 不可达,每个副本只使用进程内状态,跨 Pod 路由将不一致;
  2. 启用跨副本状态同步:设置AIBRIX_STATESYNC_ENABLED=true激活 Redis 支撑的 delta-sync 机制,将 prefix-cache 等路由状态在副本间传播。该变量默认false必须显式开启——漏配是扩展 gateway plugin 到多副本后prefix-cache路由不一致的最常见原因。

Redis 侧建议按并发请求量预留内存(大致每 1000 并发请求约 1 GiB),并通过redis_commands_duration_seconds指标监控其是否成为延迟瓶颈。

相关文档

  • 网关路由功能指南:网关配置、请求头参考、速率限制、配置档案、Prometheus 接入与 OpenTelemetry 链路追踪;
  • 生产网关部署指南:资源与副本数、Redis 多副本状态同步、buffer/连接/QPS 策略旋钮;
  • prefix-cache 算法细节:前缀缓存路由的内部机制与配置;
  • PD 分离算法细节:prefill-decode 分离的部署要求与配置;
  • 网关插件环境变量清单:全部网关环境变量的类型、默认值与源码出处。

【免费下载链接】aibrixCost-efficient and pluggable Infrastructure components for GenAI inference项目地址: https://gitcode.com/GitHub_Trending/ai/aibrix

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

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

立即咨询