网关路由#
动态路由#
首先,获取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=valuekey 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
}'
注意
过滤发生在路由策略之前。它永远不会改变路由策略认为“最佳”的 Pod。
external-filter仅在设置了routing-strategy`时才生效。它仅通过应用额外的标签约束来减少由 model.aibrix.ai/name 选择并设置的 Pod。
与 无目标 Pod 相同,如果过滤器消除了所有 Pod,请求将失败并显示
no ready pods for routing。external-filter是可选的。省略时,不应用额外过滤。
头信息说明#
本节介绍系统中用于调试和路由的各种自定义请求头。
请求头名称 |
描述 |
|---|---|
|
与客户端请求关联的唯一请求 ID,有助于调试。 |
|
指示请求头是否已正确处理。用于调试请求头解析问题。 |
|
指定路由算法选择的目标 Pod。用于验证路由决策。 |
|
定义应用于此请求的路由策略。确保遵循正确的路由逻辑。 |
|
提供了一种通用且可插拔的机制,用于在路由后进一步筛选候选 Pod。仅在设置了路由策略时应用过滤;如果没有路由算法,则跳过。 |
请求头名称 |
描述 |
|---|---|
|
识别与不正确的用户输入相关的错误。有助于客户端调试。 |
|
指示路由逻辑中存在问题,例如未能选择目标 Pod。 |
|
表示响应正文无法正确解析,通常是由于内部问题造成的。 |
|
当未识别出特定问题时,使用通用错误请求头。 |
|
标记请求正文解析问题,例如无效的 JSON。 |
|
指定请求未提供模型选项。有助于模型参数验证调试。 |
|
指示请求的模型存在但没有活动的后端 (pods)。 |
|
用户传递了 AIBrix 不支持的无效路由策略名称。 |
请求头名称 |
描述 |
|---|---|
|
表示响应流式传输期间发生错误,有助于诊断与流式传输相关的故障。 |
|
请求正文中设置的流值不正确。 |
|
指示流式响应中是否包含使用统计信息。 |
请求头名称 |
描述 |
|---|---|
|
表示 RPM(每分钟请求数)计数已成功更新 |
|
表示 TPM(每分钟令牌数)计数已成功更新 |
|
表示请求超过了允许的 RPM 阈值。 |
|
表示请求超过了允许的 TPM 阈值。 |
|
增加 RPM 计数器时遇到错误。 |
|
增加 TPM 计数器时遇到错误。 |
通过遵循这些步骤,您可以有效地调试系统中的请求处理、路由、流式传输和速率限制行为。
识别错误请求头
如果出现问题,请检查
x-error-user、x-error-routing、x-error-response-unmarshal和x-error-response-unknown以确定根本原因。对于请求处理问题,请检查
x-error-request-body-processing和x-error-no-model-in-request。
验证路由和模型分配
确保
target-pod已正确设置,以确认路由算法选择了正确的后端。如果出现
x-error-no-model-in-request或x-error-no-model-backends,请验证请求是否包含有效模型以及模型是否具有活动的后端。如果存在
x-error-invalid-routing-strategy,请确认所使用的路由策略受 AIBrix 支持。
诊断流式传输问题
如果在流式传输响应时遇到问题,请检查
x-error-streaming以查找任何报告的错误。确保为流式传输正确设置了
x-error-stream。如果流式传输响应中缺少使用统计信息,请验证
x-error-no-stream-options-include-usage。
调查速率限制问题
如果请求被阻止,请检查
x-error-rpm-exceeded或x-error-tpm-exceeded以确认其是否超出了速率限制。如果速率限制更新失败,请查找
x-error-incr-rpm或x-error-incr-tpm。成功的速率限制更新将由
x-update-rpm和x-update-tpm指示。
以下是帮助调试的入门指针。
确保以下对象的 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
检查 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