
AIBrix 生产环境模型部署实战指南路由策略、限流与副本治理【免费下载链接】aibrixCost-efficient and pluggable Infrastructure components for GenAI inference项目地址: https://gitcode.com/GitHub_Trending/ai/aibrix本指南面向将 LLM 推理服务部署到生产环境的工程师完整讲解 AIBrix 中一个模型从开发环境走向生产所需的关键配置必需的模型标签、路由策略选择、Config Profile 多流量类别支持、模型级与副本级限流RPS / Inflight、就绪探针、副本规模计算与滚动更新策略并给出上线前的可观测性检查清单。读完本文你将能够为任意一个 vLLM / SGLang 等推理服务正确打上 AIBrix 路由标签配置按流量类别隔离的限流与路由策略并安全地完成生产发布与扩容。本文主体基于 model-deployment.rst 展开并辅以 AIBrix 网关插件的源码实现作为底层原理佐证。必需标签与注解让网关认识你的模型AIBrix 网关通过 Kubernetes 标签Label识别模型并为其路由流量。每个由 AIBrix 管理的 Pod 模板至少需要两个标签缺少任何一个网关都无法将流量路由到该 Pod标签说明model.aibrix.ai/name: model-name模型标识符即客户端请求中model字段携带的模型名。每个模型必须唯一。model.aibrix.ai/port: port推理服务监听的容器端口例如8000。注意值是字符串。这两个标签的键在源码中以常量形式定义于 pkg/constants/model.go// ModelLabelName is the label for identifying the model name // Example: model.aibrix.ai/name: deepseek-llm-7b-chat ModelLabelName model.aibrix.ai/name // ModelLabelPort is the label for specifying the service port // Example: model.aibrix.ai/port: 8080 ModelLabelPort model.aibrix.ai/port除这两个必需标签外同文件中还定义了一组常用的可选标签与注解值得在生产部署中一并了解model.aibrix.ai/engine推理引擎标识如vllm。在 Prefill-Decode 解耦PD场景下网关依赖该标签区分 prefill 与 decode 角色详见 pd-disaggregation.rst。model.aibrix.ai/metric-port指标端口如8000供网关抓取引擎指标。model.aibrix.ai/config承载 JSON 格式的模型级配置含多 Profile 与限流参数本文后续章节将大量使用它。model.aibrix.ai/service-name当模型对外服务名无法作为 Kubernetes 对象名时指定其背后的 Service。model.aibrix.ai/model-router-custom-paths为 HTTPRoute 追加的路径前缀逗号分隔如/score,/version。需要留意的是模型名优先从标签读取当模型名包含标签值不允许的字符如/时也可以通过注解携带ModelNameFromMetadata 会先查标签再查注解。从源码结构看这一设计让模型命名在保留 Kubernetes 约束的同时具备灵活性。选择路由策略按工作负载类型匹配AIBrix 支持在模型级设置默认路由策略。推荐通过model.aibrix.ai/config注解显式声明而不是依赖全局的环境变量默认值——这样意图清晰且不同的模型可以共存于同一集群并使用不同的策略annotations: model.aibrix.ai/config: | { profiles: { default: { routingStrategy: least-latency } } }针对常见工作负载原文档给出了一套实用的策略起点工作负载推荐策略说明多轮对话共享系统提示词prefix-cache将重复前缀路由到已持有对应 KV cache 的 Pod减少重复 prefill 开销。独立请求批处理、摘要least-request将负载均匀分散到各 Pod。延迟敏感的交互式场景least-latency路由到近期平均延迟最低的 Pod。高吞吐推理pd分离 prefill 与 decode最大化 GPU 利用率。多用户 SLO 保障vtc-basic在用户间平衡公平性同时保持 Pod 负载饱和。各策略的完整列表与详细行为参见 Deploying Gateway 指南以及网关插件文档 gateway-plugins.rst 中的 Routing Strategies 一节。例如该节对几个关键策略的语义描述为least-request路由到当前 in-flight 请求最少的 Podleast-latency路由到平均处理延迟最低的 Podthroughput路由到累计处理加权 token 最少的 Pod倾向欠载 Podprefix-cache将请求路由到已持有与请求前缀匹配的 KV cache 的 Pod在可配置的 stddev 阈值内选择最佳前缀匹配 Pod支持本地哈希表与 KV 事件同步两种模式pdprefill-decode 解耦路由将处理拆分到专用 prefill Pod 与 decode Pod。对应实现散落在 pkg/plugins/gateway/algorithms 目录下如 least_request.go、least_latency.go、prefix_cache.go、throughput.go、pd 与 vtc每个策略都配有对应测试文件可作深入参考。Config Profile一个部署服务多类流量Config Profile 让单个模型部署同时服务多种流量类别而无需拆分多个 Deployment。生产中的常见模式是按客户端类型各定义一个 Profileannotations: model.aibrix.ai/config: | { defaultProfile: default, profiles: { default: { routingStrategy: least-latency }, batch: { routingStrategy: throughput }, pd: { routingStrategy: pd } } }客户端通过config-profile请求头选择 Profilecurl http://${ENDPOINT}/v1/chat/completions \ -H config-profile: batch \ -H Content-Type: application/json \ -d {model: my-model, messages: [{role: user, content: Summarize: ...}]}未设置该请求头时使用defaultProfile指定的 Profile若defaultProfile未设置则回退到名为default的 Profile。Profile 的源码级解析逻辑配置解析实现在 pkg/plugins/gateway/configprofiles/configprofiles.go核心数据结构为type ModelConfigProfiles struct { LockedRoutingStrategy string json:lockedRoutingStrategy,omitempty DefaultProfile string json:defaultProfile Profiles map[string]ModelConfigProfile json:profiles } type ModelConfigProfile struct { RoutingStrategy string json:routingStrategy RoutingConfig json.RawMessage json:routingConfig,omitempty RequestsPerSecond int64 json:requestsPerSecond,omitempty RequestsPerSecondPerReplica float64 json:requestsPerSecondPerReplica,omitempty RequestsInflight int64 json:requestsInflight,omitempty }该包还支持config-profile: auto的自动选择每个 Profile 的routingConfig内可声明promptTokensGte、promptTokensLt、maxTokensGte、maxTokensLt等请求级选择提示网关根据请求的实际 token 特征RequestFeatures挑选最匹配的 Profile提示条件越具体优先级越高见 ResolveAutoProfileName。此外lockedRoutingStrategy可在模型级锁定路由策略优先级高于请求头、Profile 内策略以及ROUTING_ALGORITHM环境变量。模型级吞吐上限RPS 限流是什么requestsPerSecond设置网关转发到某个模型的每秒请求数硬上限。超出上限的请求在路由和推理发生之前就被立即拒绝返回 HTTP429 Too Many Requests。这是一个模型级上限所有用户合计区别于按用户维度的 RPM/TPM 限制。典型用途保护模型免受突发流量冲击在共享集群中为模型执行成本预算GPU 小时数为同一网关上更高优先级的模型预留余量。如何配置在模型model.aibrix.ai/config注解的对应 Profile 中添加requestsPerSecondannotations: model.aibrix.ai/config: | { profiles: { default: { routingStrategy: least-latency, requestsPerSecond: 50 } } }要为不同流量类别设置不同上限可按 Profile 分别配置annotations: model.aibrix.ai/config: | { defaultProfile: default, profiles: { default: { routingStrategy: least-latency, requestsPerSecond: 100 }, batch: { routingStrategy: throughput, requestsPerSecond: 20 } } }上例中交互式流量defaultProfile上限为 100 RPS批处理流量batchProfile上限为 20 RPS。触发限流时客户端看到什么HTTP/1.1 429 Too Many Requests x-error-model-rps-exceeded: true {error: {message: model: my-model has exceeded RPS: 50, type: rate_limit_error, code: rate_limit_exceeded}}内部工作原理计数器存储在 Redis 中每个请求到达时原子递增1 秒窗口自动重置。若计数器递增后路由失败例如没有就绪 Pod递增会被回滚保证失败的请求不消耗配额。源码实现位于 gateway_ratelimit.go 的enforceModelRPS与decrModelRPS预路由门enforceModelRPS在路由前调用。先通过modelRateLimiter.Incr(..., 1)原子递增并取回新值若newVal limit则返回 429并立即用Incr(..., -1)回滚这次未获准的递增若newVal limit则放行。延迟补偿decrModelRPS预充值成功后随即注册。若后续路由失败则退还配额Incr(..., -1)若路由成功且请求记账完成补偿被取消预充值计数保留。采用先递增再检查incr-then-check而非先检查再递增是因为INCRBY是唯一的准入关口Redis 对其原子执行每个并发调用者都会拿到唯一的顺序结果从而消除了 check→increment 窗口期的 TOCTOU 竞态、避免超量准入。底层限流器接口定义于 pkg/plugins/gateway/ratelimiter/rate_limiter.goRedis 实现见 pkg/plugins/gateway/ratelimiter/redis.go采用固定窗口计数器key 结构为{name}:{key}:{timebin}时间桶按(now / windowSeconds) % 64计算循环 64 个桶旧桶自动过期Incr通过 Lua 脚本incrAndExpireScript原子执行INCRBY并按需设置 TTL仅当 key 尚无 TTL 时即PTTL -1避免持续重试 429 的客户端反复延长窗口。详细设计见 ratelimiter/README.md。注意requestsPerSecond要求网关插件启用 Redis 才能跨副本生效。未启用 Redis 时计数器仅存于进程内无法在多个网关副本间共享。参见 Deploying Gateway 指南中的 Enabling Redis for Multi-Replica Deployments。省略requestsPerSecond或将其设为0即可禁用该限制。随副本数伸缩的 RPS 上限是什么requestsPerSecondPerReplica设置每副本的 RPS 上限而非固定模型级上限。网关将其乘以模型当前的可路由副本数得出有效的聚合上限因此限流会随模型扩缩容自动伸缩。当同一 Profile 同时设置了requestsPerSecondPerReplica与requestsPerSecond时前者优先生效。设置requestsPerSecondPerReplica还会强制将该 Profile 的路由策略改为least-request覆盖 Profile 中声明的任何routingStrategy因为每副本限流只有在流量被均匀分摊到各副本时才能作为聚合值成立。如何配置annotations: model.aibrix.ai/config: | { profiles: { default: { routingStrategy: least-latency, requestsPerSecondPerReplica: 10 } } }例如4 个可路由副本时有效聚合上限为 40 RPS扩容到 8 个副本后自动提升至 80 RPS无需修改注解。支持小数取值如0.5用于低于 1 RPS 的限流内部表达为 每 N 秒 1 个请求。推导出的限流值总是向下取整保证实际投递速率不会超过配置值——例如0.18会被转换为每 6 秒 1 个请求约 0.167 RPS而不是每 5 秒 1 个约 0.2 RPS超出配置。这一取整逻辑与子 1 RPS 场景的窗口换算在 replica_rps_test.go 等测试中有所覆盖。触发限流时客户端看到什么与普通requestsPerSecond相同见上文因为每副本数值在强制前已被解析为聚合requestsPerSecond值。注意与requestsPerSecond一样requestsPerSecondPerReplica需要网关插件启用 Redis 才能在集群范围内强制执行。且requestsPerSecondPerReplica与下文requestsInflight均没有环境变量形式——两者都直接在 Profile 中配置。每副本并发上限Inflight 限流是什么requestsInflight限制单个副本上允许的并发in-flight请求数。与上述 RPS 限制不同它按 Pod 而非集群聚合强制因此无需随副本数伸缩——无论模型有多少副本该上限都成立。设置requestsInflight同样会强制路由策略为least-request原因与requestsPerSecondPerReplica一致只有当路由策略确实为请求选中单个目标 Pod 时每 Pod 上限才能被强制。requestsInflight与requestsPerSecondPerReplica是相互独立的限制可以同时设置例如 每个副本最多 3 个并发请求且每副本不超过 5 RPS。若requestsInflight配置值低于解析出的每副本 RPS网关会记录警告提示 RPS 上限实际上可能无法达到但保持并发上限不变而不会放宽。如何配置annotations: model.aibrix.ai/config: | { profiles: { default: { routingStrategy: least-latency, requestsInflight: 3 } } }触发限流时客户端看到什么当每个可路由副本都达到 inflight 上限时网关返回HTTP/1.1 429 Too Many Requests x-error-model-replica-inflight-exceeded: true {error: {message: model: my-model has exceeded replica inflight limit: 3, type: overloaded_error, code: replica_inflight_exceeded}}内部工作原理每个 Pod 的进行中请求数记录在 Redis 中随请求开始与结束原子更新因此跨共享同一 Redis 实例的所有网关副本都成立。准入是原子的一次往返内完成递增与检查并发落在同一 Pod 的请求即便来自不同网关实例也无法在同一轮检查中全部越过上限。实现见 gateway_inflight.goenforceReplicaInflight在目标 Pod 已选出后调用通过s.cache.AdmitPodRunningRequest(pod.Name, pod.Namespace, limit)原子地预留该请求的并发额度而非先读后写避免并发请求观察到同一份未递增计数而全部被放行准入成功即置位ReplicaInflightAdmitted避免后续请求记账重复计数。filterSaturatedReplicaInflight作为尽力而为的预过滤一次 Redis 往返批量读取候选 Pod 的 running-request 数将已达上限的 Pod 从候选中剔除引导选择避开饱和副本真正的硬上限仍由enforceReplicaInflight的原子准入把关因此预过滤即使因 Redis 抖动失败fail-open至多只会路由到饱和 Pod 再被拒绝不会绕过上限本身。触发时由replicaInflightExceededResponse构造 429 响应并携带x-error-model-replica-inflight-exceeded: true头。注意网关插件未启用 Redis 时requestsInflight回退为本地进程内计数仅按单个网关副本强制而非针对模型副本的集群级强制。省略requestsInflight或将其设为0即可禁用该限制。就绪与健康检查网关只将流量路由到 Kubernetes 判定为Ready的 Pod。请确保就绪探针在推理服务完整加载模型之后才将 Pod 标记为就绪——对于大模型这可能耗时数分钟。针对 vLLM 的实用就绪探针示例readinessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 60 periodSeconds: 10 failureThreshold: 30 # allow up to 5 minutes for model load若 Pod 在曾处于就绪状态后未能通过就绪探针例如发生 OOM网关会立即停止向其路由同时不中断已 in-flight 的请求。副本规模估算不存在放之四海皆准的公式但下面是一个实用的起点测量单副本容量——以递增的 QPS 运行短时压测直至延迟或错误率劣化记录可持续的 QPS留出安全余量——以测得峰值的 60%–70% 为目标为突发留出空间计算副本数——replicas ceil(target_QPS / sustainable_QPS_per_replica)。对于 PD 解耦部署需要分别为 prefill 与 decode Pod 计算规模prefill Pod 是计算密集型高输入 token 负载时应增加decode Pod 是内存带宽密集型长输出负载时应增加。PD 的角色划分与桶配置细节可参见 pd-disaggregation.rst。滚动更新策略LLM Pod 启动耗时很长。在滚动发布时配置maxUnavailable: 0与maxSurge: 1或更高确保发布期间不损失容量spec: strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 0 maxSurge: 1maxUnavailable: 0意味着 Kubernetes只有在新 Pod 通过就绪探针后才终止旧 Pod从而防止网关把流量路由到尚未完成模型加载的 Pod。对于 PD 解耦部署应分开发布prefill 与 decode Pod——两者同时更新可能使部分 roleset 暂时不完整导致网关跳过它们。上线前可观测性检查清单在生产发布前确保你对以下指标具备可见性每模型请求速率——aibrix_gateway_requests_total计数器按model标签细分路由延迟——请求到达与 Pod 选择之间的耗时RPS 限流拒绝——关注x-error-model-rps-exceeded响应头或对应指标Pod 就绪抖动——对在 Ready 与 NotReady 之间反复切换的 Pod 设置告警这通常意味着 OOM 或不稳定Prefill 超时率仅 PD——pd-prefill-request-error日志条目高比率表明 prefill Pod 过载。完整指标参考见 Observability 指南。生产发布路径速览综合本文要点一次标准的生产模型发布流程为在 Pod 模板上打上model.aibrix.ai/name与model.aibrix.ai/port两个必需标签通过model.aibrix.ai/config注解声明profiles为每类流量设置routingStrategy并按需配置requestsPerSecond/requestsPerSecondPerReplica/requestsInflight确认网关插件已启用 Redis多副本部署时为跨副本一致的限流与路由决策所必需并参考 Deploying Gateway 调整网关插件与 Envoy Proxy 的副本数和资源为推理服务配置就绪探针等待模型加载完成设置合理的initialDelaySeconds、periodSeconds与failureThreshold按 60%–70% 峰值余量估算副本数为滚动更新配置maxUnavailable: 0上线后按可观测性检查清单逐项核对指标与告警。后续还可结合 autoscaling 为部署配置自动扩缩容或通过 kvcache-offloading 复用 KV cache 降低 prefill 成本。【免费下载链接】aibrixCost-efficient and pluggable Infrastructure components for GenAI inference项目地址: https://gitcode.com/GitHub_Trending/ai/aibrix创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考