
在大模型(LLM)推理服务中,如何高效地进行流量调度是一个核心挑战。不同于传统的微服务,LLM请求具有长耗时、高并发、对GPU显存敏感等特点。Aibrix 作为一款专为 GenAI 设计的云原生基础设施,巧妙地结合了 Envoy Proxy 的强大流量治理能力,实现了一套智能的 LLM 流量转发机制。
本文将深入探讨 Aibrix 是如何利用 Envoy 及 Envoy Gateway 构建其流量转发层的。
Envoy Proxy 是一个开源的高性能边缘和服务代理,最初由 Lyft 开发。它专为云原生应用设计,已成为现代服务网格(Service Mesh)和 API 网关的事实标准。通俗来讲,它就是一个类似于Nginx的反向代理服务器,只不过支持更加贴合Kubernetes的配置,成为云原生时代的宠儿。
在 v1.36.2 版本中,Envoy 继续巩固了其作为“通用数据平面”的地位。对于 LLM 场景,Envoy 的以下特性尤为关键:
简单来说,xDS 是 Envoy(数据面)和管理服务器(控制面)之间“对话”的语言。Envoy 通过这个协议,动态地获取它需要的所有配置信息,而不需要重启。
“x” 代表各种资源,”DS” 代表 Discovery Service(发现服务)。 Envoy 需要发现很多东西,所以有一系列的 API:
xDS 最常用的模式是基于 gRPC 长连接 的流式传输。
只要配置有更新,服务器就会主动推给 Envoy,不需要 Envoy 一直问。
xDS 协议有四种传输变体来告诉xDS该如何传递各种资源,主要区别在于全量还是增量,以及单路还是多路。
A. 最终一致性 (Eventual Consistency)
xDS 是最终一致的。这意味着在更新过程中,可能会有短暂的时间,配置还没完全同步。为了不丢流量,更新顺序很有讲究。
加服务:先推 CDS (集群) -> 再推 EDS (IP) -> 最后推 RDS (路由指向它)。
下线服务:先推 RDS (路由切走) -> 再删 CDS/EDS。
B. 资源预热 (Warming)
Envoy 很谨慎,不会拿到配置立马就用,而是要先“热身”。
比如收到一个新的 Cluster 配置,Envoy 不会立刻把流量导过去,而是会先去获取这个 Cluster 对应的 Endpoint (IP列表)。只有当 IP 列表也拿到了,Envoy 才会觉得这个 Cluster 准备好了(Warmed),才开始往里面导流量。这避免了把流量导向一个空壳子。
虽然 Envoy 功能强大,但其配置(xDS 协议)极其复杂。为了简化在 Kubernetes 环境下的使用,Envoy Gateway (EG) 应运而生。
Envoy Gateway 是 Kubernetes Gateway API 的一种实现。它扮演控制平面(Control Plane)的角色,将 Kubernetes 的高层资源(如 Gateway, HTTPRoute)翻译成 Envoy 能够理解的底层 xDS 配置。这使得运维人员可以用标准的 K8s YAML 来管理复杂的网关规则,而无需手写数千行的 Envoy 配置文件。

Aibrix 是一个开源的、云原生的 GenAI 推理基础设施。它的核心目标是解决 LLM 推理中的成本、性能和扩展性问题。不同于传统的 Kubernetes 调度器或通用的微服务网关,Aibrix 深入理解 LLM 的运行特征,构建了一套“模型感知”的调度与路由体系。
在 LLM 推理场景中,我们面临着独特的挑战:
Aibrix 的架构设计遵循控制面与数据面分离的原则,同时引入了专门的“智能层”来处理复杂的调度逻辑:
通过这种架构,Aibrix 实现了从“流量进入”到“模型计算”的全链路优化,而 Envoy 在其中扮演了连接“业务意图”与“底层算力”的关键桥梁角色。
Aibrix 并没有重新造轮子去写一个高性能网关,而是站在了 Envoy 的肩膀上。它利用 Envoy Gateway 作为流量入口,并通过 External Processing (ExtProc) 机制注入了“AI 智能”。
Aibrix 的流量转发架构可以概括为:数据面由 Envoy 承载,控制面由 Aibrix Plugin 决策。
上图展示了 Aibrix 环境下一次典型的 LLM 推理请求流程:
用户发起 HTTP POST 请求(如 /v1/chat/completions),经过集群的负载均衡器到达 Aibrix Gateway (Envoy Proxy)。
Aibrix在安装的时候会定义一个名为 aibrix-eg 的 GatewayClass 来告诉 Kubernetes Gateway API 使用 Envoy Gateway 作为 Aibrix 数据面流量 Gateway API 的控制器(Controller)。 随后创建一个名为 aibrix-eg 的 Gateway,所属 GatewayClass 为之前创建的 aibrix-eg(吐槽一下这命名 :( )。 Envoy的控制器监测到 aibrix-eg Gateway 的创建后,会在自己的命名空间下启动一个 Envoy Proxy Pod 做实际的流量转发(反向代理)
Aibrix 会利用 Envoy Gateway 的 Extensions 机制针对 aibrix-eg Gateway 做了一些配置:
Aibrix同样会创建一个名字为 aibrix-reserved-router 的 HTTPRoute 将如下路径的流量路由到 Aibrix Envoy Plugin(兜底用,大部分情况下,流量已经通过 Plugin 及上述的 EnvoyPatchPolicy 被转发到了最优的推理服务)。
创建名为 aibrix-reserved-router-metadata-endpoint 的 HTTPRoute 将如下路径的流量路由到 Aibrix Metadata Service。
Envoy Proxy 不会立即转发给后端推理服务,而是通过 EnvoyExtensionPolicy 接口拦截请求,将其 Header 及 Body 通过 gRPC 发送给 Aibrix Gateway Plugin(即图中的 “The Brain”)或者 Aibrix Metadata Service。Aibrix根据请求头和请求体及自身存储的信息来决定将流量路由到哪个推理服务,然后设置 routing-strategy 和 target-pod Header,让 Envoy Proxy 将流量路由到指定的推理服务。
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyExtensionPolicy
metadata:
name: aibrix-gateway-plugins-extension-policy
namespace: {{ .Release.Namespace }}
labels:
{{- include "chart.labels" . | nindent 4 }}
app.kubernetes.io/component: aibrix-gateway-plugin
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: aibrix-reserved-router
extProc:
- backendRefs:
- name: aibrix-gateway-plugins
port: 50052
processingMode:
request:
body: Buffered
response:
body: Streamed
messageTimeout: {{ .Values.gatewayPlugin.messageTimeout }}model, message, stream, errRes := validateRequestBody(requestID, requestPath, body.RequestBody.GetBody(), user)
if errRes != nil {
return errRes, model, routingCtx, stream, term
}
routingCtx.Model = model
routingCtx.Message = message
routingCtx.ReqBody = body.RequestBody.GetBody()Aibrix Gateway Plugin 中的 RouteManager 作为 Aibrix 路由算法实现的核心模块,其主要职责是管理、注册、初始化和选择不同的路由策略(例如:随机路由、轮询路由、基于缓存的亲和性路由等)。当 Envoy 将请求转发给 Plugin 时,Plugin 并不直接写死处理逻辑,而是通过这个 RouterManager 来动态获取处理方案。
以下是 Aibrix Plugin 处理一个请求时的完整工作流:
对应代码中的 Select 方法:
// 运行时核心方法:根据上下文决定使用哪个路由对象
func (rm *RouterManager) Select(ctx *types.RoutingContext) (types.Router, error) {
rm.routerMu.RLock()
defer rm.routerMu.RUnlock()
// 1. 尝试查找用户指定的算法 (例如 "cache-affinity")
if provider, ok := rm.routerFactory[ctx.Algorithm]; ok {
// 2. 如果找到了,返回对应的 Router 实例
return provider(ctx)
} else {
// 3. 【容错机制】如果用户指定的策略不存在,自动降级为随机路由 (Random)
// 保证请求不会因为策略拼写错误而失败
klog.Warningf("Unsupported router strategy: %s, use %s instead.", ctx.Algorithm, RouterRandom)
return RandomRouter, nil
}
}通过这样的设计,路由选择可实现:
拿到具体的 Router 对象后,Plugin 会调用该对象的计算方法。但在 AI 推理场景中,智能路由(如基于缓存的路由)可能会失败(例如:缓存所在的 Pod 挂了,或者显存满了)。这时,工作流会进入 Fallback(回退)流程。对应代码中的 SetFallback 逻辑:
// 配置路由失败时的备选方案
func (rm *RouterManager) SetFallback(router types.Router, fallback types.RoutingAlgorithm) error {
// ... 检查类型 ...
// 1. 确保系统已初始化完成
<-rm.routerInited.Done()
// ...
// 2. 为当前路由绑定一个“备胎”
if provider, ok := rm.routerFactory[fallback]; !ok {
return ErrFallbackNotRegistered
} else {
// 告诉主路由:如果你搞不定,就用这个 fallback 算法
r.SetFallback(fallback, provider)
}
return nil
}最终,选定的 Router 计算出目标 Pod 的 IP。Plugin 将这个 IP 放入 target-pod Header 中,通过 gRPC 返回给 Envoy。Envoy 随后根据我们在 YAML 中看到的 original_destination_cluster 配置,将流量转发给该 Pod。
Aibrix 通过将 Envoy 的高性能数据面 与 自定义 Go 插件的智能控制面 相结合,完美解决了 LLM 推理服务中“状态感知”这一核心难题。
这种“双层调度”架构——Kubernetes 负责资源(Pod)的生命周期,Aibrix 负责请求(Request)的智能分发——为构建高效、低成本的 GenAI 基础设施提供了极佳的范例。