网关路由#

动态路由#

首先,获取Envoy代理访问网关的外部IP和端口。

NAME                                     TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                                   AGE
envoy-aibrix-system-aibrix-eg-903790dc   LoadBalancer   10.96.239.246   101.18.0.4    80:32079/TCP                              10d
envoy-gateway                            ClusterIP      10.96.166.226   <none>        18000/TCP,18001/TCP,18002/TCP,19001/TCP   10d

在模型或 LoRA 适配器部署中,它们各自的控制器会创建一个 HTTPRoute 对象,网关会动态发现该对象以转发用户请求。请务必验证 HTTPRoute 状态为 Accepted。

$ kubectl get httproute -A
NAMESPACE       NAME                                  HOSTNAMES   AGE
aibrix-system   aibrix-reserved-router                            17m # reserved router
aibrix-system   deepseek-r1-distill-llama-8b-router               14m # created for each model deployment
....
$ kubectl describe httproute deepseek-r1-distill-llama-8b-router -n aibrix-system
Name:         deepseek-r1-distill-llama-8b-router
Namespace:    aibrix-system
Labels:       <none>
Annotations:  <none>
API Version:  gateway.networking.k8s.io/v1
Kind:         HTTPRoute
Metadata:
  Creation Timestamp:  2025-02-16T17:56:03Z
  Generation:          1
  Resource Version:    2641
  UID:                 2f3f9620-bf7c-487a-967e-2436c3809178
Spec:
  Parent Refs:
    Group:      gateway.networking.k8s.io
    Kind:       Gateway
    Name:       aibrix-eg
    Namespace:  aibrix-system
  Rules:
    Backend Refs:
      Group:
      Kind:       Service
      Name:       deepseek-r1-distill-llama-8b
      Namespace:  default
      Port:       8000
      Weight:     1
    Matches:
      Headers:
        Name:   model
        Type:   Exact
        Value:  deepseek-r1-distill-llama-8b
      Path:
        Type:   PathPrefix
        Value:  /
    Timeouts:
      Request:  120s
Status:
  Parents:
    Conditions:
      Last Transition Time:  2025-02-16T17:56:03Z
      Message:               Route is accepted
      Observed Generation:   1
      Reason:                Accepted
      Status:                True
      Type:                  Accepted
      Last Transition Time:  2025-02-16T17:56:03Z
      Message:               Resolved all the Object references for the Route
      Observed Generation:   1
      Reason:                ResolvedRefs
      Status:                True
      Type:                  ResolvedRefs
    Controller Name:         gateway.envoyproxy.io/gatewayclass-controller
    Parent Ref:
      Group:      gateway.networking.k8s.io
      Kind:       Gateway
      Name:       aibrix-eg
      Namespace:  aibrix-system
Events:           <none>

在 v0.5.0 中,HTTPRoute.Spec.Rules.Matches 中的默认 PathPrefix 配置仅包含以下端点

要添加自定义路径前缀,您必须在部署清单(或 modelAdapter、RayClusterFleet)中使用 model.aibrix.ai/model-router-custom-paths 注解指定它们。

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    model.aibrix.ai/name: deepseek-r1-distill-llama-8b
    model.aibrix.ai/port: "8000"
  annotation:
    model.aibrix.ai/model-router-custom-paths: /version,/score # Note: split by ',' and ignore any space or empty path
  name: deepseek-r1-distill-llama-8b
  namespace: default

在大多数 Kubernetes 设置中,LoadBalancer 默认受支持。您可以使用以下命令检索外部 IP

LB_IP=$(kubectl get svc/envoy-aibrix-system-aibrix-eg-903790dc -n envoy-gateway-system -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
ENDPOINT="${LB_IP}:80"

模型名称(例如 deepseek-r1-distill-llama-8b)必须与部署中的标签 model.aibrix.ai/name 匹配。

curl -v http://${ENDPOINT}/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
    "model": "deepseek-r1-distill-llama-8b",
    "messages": [{"role": "user", "content": "Say this is a test!"}],
    "temperature": 0.7
}'

注意

AIBrix 将公共端点暴露给互联网。请启用身份验证以保护您的端点。如果是 vLLM,您可以传入参数 --api-key 或环境变量 VLLM_API_KEY 以使服务器检查请求头中的 API 密钥。有关更多详细信息,请查看 vLLM OpenAI 兼容服务器

启用身份验证后,您可以这样使用 -H Authorization: bearer your_key 查询模型

  curl -v http://${ENDPOINT}/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer any_key" \
  -d '{
      "model": "deepseek-r1-distill-llama-8b",
      "messages": [{"role": "user", "content": "Say this is a test!"}],
      "temperature": 0.7
  }'

路由策略#

以下是网关支持的路由策略

  • random:将请求路由到随机 Pod。

  • least-request:将请求路由到正在进行请求最少的 Pod。

  • throughput:将请求路由到已处理总加权令牌数最少的 Pod。

  • prefix-cache:将请求路由到已具有与请求提示前缀匹配的 KV 缓存的 Pod,包括负载均衡和多轮对话。

  • least-busy-time:将请求路由到累计忙碌处理时间最少的 Pod。

  • least-kv-cache:将请求路由到当前 KV 缓存大小最小(VRAM 使用最少)的 Pod。

  • least-latency:将请求路由到平均处理延迟最低的 Pod。

  • prefix-cache-preble:在考虑前缀缓存命中和 Pod 负载的情况下路由请求,实现基于 Preble:LLM 服务的高效分布式提示调度:https://arxiv.org/abs/2407.00023

  • vtc-basic:使用混合分数平衡公平性(用户令牌计数)和 Pod 利用率来路由请求。它是虚拟令牌计数器 (VTC) 算法的一个简单变体。更多详细信息请参见 Ying1123/VTC-artifact

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
}'
  • pd:用于预填充-解码解聚合的路由请求,将处理分摊到预填充和解码 Pod 之间以优化性能。

curl -v http://${ENDPOINT}/v1/chat/completions \
-H "routing-strategy: pd" \
-H "Content-Type: application/json" \
-d '{
    "model": "your-model-name",
    "messages": [{"role": "user", "content": "Say this is a test!"}],
    "temperature": 0.7
}'
  • session-affinity:通过将目标 Pod 的地址 (IP:Port) 编码为 base64 值,再存入 x-session-id 请求头中,从而实现粘性会话路由。在后续请求中,如果此请求头存在且有效,网关会尝试路由到同一 Pod。如果该 Pod 不再就绪(例如,已缩容或被驱逐),它将回退到选择一个随机的就绪 Pod 并发出新的会话 ID。

curl -v http://${ENDPOINT}/v1/chat/completions \
-H "routing-strategy: session-affinity" \
-H "Content-Type: application/json" \
-d '{
    "model": "your-model-name",
    "messages": [{"role": "user", "content": "Say this is a test!"}],
    "temperature": 0.7
}'
会话亲和性如何工作
  • 在第一个请求(没有 x-session-id)时,网关会选择一个随机的就绪 Pod 并在响应中返回 x-session-id 请求头。

  • 客户端应存储此请求头并在后续请求(例如,多轮对话)中重新发送。

  • 网关解码会话 ID 以恢复原始 Pod 地址并尝试重用它。

  • 如果该 Pod 不可用,它会透明地故障转移到新 Pod 并发出新的会话 ID。

  • 这对于多轮聊天应用程序特别有用,因为在同一后端实例上保持上下文可以提高性能和一致性。

x-session-id 请求头不是安全令牌——它只编码网络位置。请勿将其用于身份验证或授权。

速率限制#

网关支持基于 user 头进行速率限制。您可以为每个 user 指定一个唯一标识符,以应用每分钟请求数 (RPM) 或每分钟令牌数 (TPM) 等速率限制。此 user 头对于为每个客户端启用速率限制支持至关重要。如何在 aibrix 中管理用户?请参阅 [用户管理](vllm-project/aibrix)

要设置速率限制,请在请求中添加 user 请求头,如下所示

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

注意

将“your-user-id”替换为每个用户的唯一标识符。此标识符允许网关基于每个用户强制执行速率限制。如果需要速率限制支持,请确保此 user 请求头始终在请求中设置。如果您不需要速率限制,则无需设置此请求头。

外部过滤器#

external-filter 请求头在路由策略选择最佳目标 Pod 之前进行评估。允许用户使用 Kubernetes labelSelector 表达式动态限制目标 Pod。

请求头值遵循 Kubernetes 标签选择器语法

  • key=value

  • key in (a, b)

  • key!=value

  • 逗号分隔的选择器列表

标签选择器语法参考:https://kubernetes.ac.cn/docs/concepts/overview/working-with-objects/labels/

curl -v http://${ENDPOINT}/v1/completions \
   -H "Content-Type: application/json" \
   -H "routing-strategy: random" \
   -H "external-filter: environment=production,tier=frontend" \
   -d '{
         "model": "deepseek-r1-distill-llama-8b",
         "prompt": "San Francisco is a",
         "max_tokens": 128,
         "temperature": 0
       }'

注意

  1. 过滤发生在路由策略之前。它永远不会改变路由策略认为“最佳”的 Pod。

  2. external-filter 仅在设置了 routing-strategy` 时才生效。

  3. 它仅通过应用额外的标签约束来减少由 model.aibrix.ai/name 选择并设置的 Pod。

  4. 无目标 Pod 相同,如果过滤器消除了所有 Pod,请求将失败并显示 no ready pods for routing

  5. external-filter 是可选的。省略时,不应用额外过滤。

头信息说明#

本节介绍系统中用于调试和路由的各种自定义请求头

请求头名称

描述

request-id

与客户端请求关联的唯一请求 ID,有助于调试。

x-went-into-req-headers

指示请求头是否已正确处理。用于调试请求头解析问题。

target-pod

指定路由算法选择的目标 Pod。用于验证路由决策。

routing-strategy

定义应用于此请求的路由策略。确保遵循正确的路由逻辑。

external-filter

提供了一种通用且可插拔的机制,用于在路由后进一步筛选候选 Pod。仅在设置了路由策略时应用过滤;如果没有路由算法,则跳过。

请求头名称

描述

x-error-user

识别与不正确的用户输入相关的错误。有助于客户端调试。

x-error-routing

指示路由逻辑中存在问题,例如未能选择目标 Pod。

x-error-response-unmarshal

表示响应正文无法正确解析,通常是由于内部问题造成的。

x-error-response-unknown

当未识别出特定问题时,使用通用错误请求头。

x-error-request-body-processing

标记请求正文解析问题,例如无效的 JSON。

x-error-no-model-in-request

指定请求未提供模型选项。有助于模型参数验证调试。

x-error-no-model-backends

指示请求的模型存在但没有活动的后端 (pods)。

x-error-invalid-routing-strategy

用户传递了 AIBrix 不支持的无效路由策略名称。

请求头名称

描述

x-error-streaming

表示响应流式传输期间发生错误,有助于诊断与流式传输相关的故障。

x-error-stream

请求正文中设置的流值不正确。

x-error-no-stream-options-include-usage

指示流式响应中是否包含使用统计信息。

请求头名称

描述

x-update-rpm

表示 RPM(每分钟请求数)计数已成功更新

x-update-tpm

表示 TPM(每分钟令牌数)计数已成功更新

x-error-rpm-exceeded

表示请求超过了允许的 RPM 阈值。

x-error-tpm-exceeded

表示请求超过了允许的 TPM 阈值。

x-error-incr-rpm

增加 RPM 计数器时遇到错误。

x-error-incr-tpm

增加 TPM 计数器时遇到错误。

通过遵循这些步骤,您可以有效地调试系统中的请求处理、路由、流式传输和速率限制行为。

  1. 识别错误请求头

    • 如果出现问题,请检查 x-error-userx-error-routingx-error-response-unmarshalx-error-response-unknown 以确定根本原因。

    • 对于请求处理问题,请检查 x-error-request-body-processingx-error-no-model-in-request

  2. 验证路由和模型分配

    • 确保 target-pod 已正确设置,以确认路由算法选择了正确的后端。

    • 如果出现 x-error-no-model-in-requestx-error-no-model-backends,请验证请求是否包含有效模型以及模型是否具有活动的后端。

    • 如果存在 x-error-invalid-routing-strategy,请确认所使用的路由策略受 AIBrix 支持。

  3. 诊断流式传输问题

    • 如果在流式传输响应时遇到问题,请检查 x-error-streaming 以查找任何报告的错误。

    • 确保为流式传输正确设置了 x-error-stream

    • 如果流式传输响应中缺少使用统计信息,请验证 x-error-no-stream-options-include-usage

  4. 调查速率限制问题

    • 如果请求被阻止,请检查 x-error-rpm-exceededx-error-tpm-exceeded 以确认其是否超出了速率限制。

    • 如果速率限制更新失败,请查找 x-error-incr-rpmx-error-incr-tpm

    • 成功的速率限制更新将由 x-update-rpmx-update-tpm 指示。

以下是帮助调试的入门指针。

  1. 确保以下对象的 status.conditions == Accepted。

kubectl describe gatewayclass -n aibrix-system

kubectl describe gateway -n aibrix-system

kubectl describe envoypatchpolicy -n aibrix-system

# check for all objects
kubectl describe envoyextensionpolicy -n aibrix-system

# check for all objects
kubectl describe httproute -n aibrix-system
  1. 检查 envoy 代理和 aibrix-gateway-plugins 的日志。如果创建了 GitHub issue,请复制日志。

kubectl get pods -n envoy-gateway-system

NAME                                                      READY   STATUS    RESTARTS   AGE
envoy-aibrix-system-aibrix-eg-903790dc-84ccfcbc6b-hw2lq   2/2     Running   0          13m
envoy-gateway-7c7659ffc9-rvm5s                            1/1     Running   0          16m

kubectl logs envoy-aibrix-system-aibrix-eg-903790dc-84ccfcbc6b-hw2lq -n envoy-gateway-system
kubectl get pods -n aibrix-system

NAME                                        READY   STATUS             RESTARTS   AGE
aibrix-controller-manager-fb4495448-j9k6g   1/1     Running            0          22m
aibrix-gateway-plugins-6bd9fcd5b9-2bwpr     1/1     Running            0          22m
aibrix-gpu-optimizer-df9db96c8-2fctd        1/1     Running            0          22m
aibrix-kuberay-operator-5bf4985d86-7g4tz    1/1     Running            0          22m
aibrix-metadata-service-9d4cd7f77-mq7tr     1/1     Running            0          22m
aibrix-redis-master-7d6b77c794-bcqxc        1/1     Running            0          22m

kubectl logs aibrix-gateway-plugins-6bd9fcd5b9-2bwpr -n aibrix-system