配置令牌配额
简介
Envoy AI Gateway 可以根据 令牌用量 而不是请求数量进行限流,并基于身份为每个调用方跟踪独立预算。这可以防止单个消费者或失控的智能体耗尽共享的模型预算,并且让你能够在同一个网关上提供按用户、按部门以及按层级划分的令牌配额。
一个令牌配额由三部分组成:
AIGatewayRoute.llmRequestCosts将每个 LLM 响应中的令牌计数提取到 Envoy 动态元数据中。- 全局限流后端(Redis)累积该成本。由于令牌成本只有在响应之后才知道,因此不能由按 Pod 的本地限流器来跟踪。
- 类型为
Global的BackendTrafficPolicy定义预算和身份键。
使用场景
- 为每个用户在昂贵模型上提供每月令牌预算,并为高级层级提供更高预算。
- 限制某个部门通过其所有应用程序可消耗的总令牌数。
- 保护共享模型,防止某个行为异常的自动化账户过度消耗。
前提条件
-
已安装 Envoy AI Gateway,并且有一个
AIGatewayRoute正在路由到你的模型后端。请确认相关 CRD 已存在: -
调用方身份通过请求头传递,例如
x-user-id。请参见 验证消费者身份。如果没有身份头,下面的预算会退化为所有调用方共享的单一计数器,因此这一步决定了配额是否 按消费者 生效。 -
已有一个 Redis 实例可用。默认提供程序请使用 Redis 缓存服务 中的托管实例,然后记录其访问地址(
host:port)和凭证。在继续之前,请先验证集群可以访问该实例: -
记下
Gateway的名称和命名空间——后续需要它们来重启正确的数据平面代理:
请在专用命名空间中创建 Gateway 和 AIGatewayRoute(例如 maas-system),而不要放在 Envoy Gateway 控制平面命名空间 envoy-gateway-system 中。放置在控制平面命名空间中的网关,可能不会将 AI Gateway 请求处理过滤器和 SecurityPolicy 应用到其监听器,这会静默破坏路由和策略执行。请参见 Envoy AI Gateway。
步骤
启用全局限流后端
本地限流器无法累积来自响应的令牌成本,因此网关必须使用由 Redis 支持的 Global Rate Limit 服务。通过 Redis 缓存服务 创建一个 Redis 实例,并从实例详情页复制其访问地址。然后将该地址设置到 envoy-gateway-config ConfigMap(命名空间 envoy-gateway-system)中的 data."envoy-gateway.yaml" 下:
在顶层配置下添加 rateLimit 块(保留现有键,例如 gateway: 和 provider: 不变):
<redis-host>:<redis-port>:从 Redis 实例详情页复制的访问地址。- 对于受密码保护的 Redis,请使用标准 Redis URI 形式将凭证嵌入 URL 中:
url: redis://<username>:<password>@<redis-host>:<redis-port>(仅密码认证时省略<username>:)。Envoy Gateway v1.5.x 在rateLimit.backend.redis下只暴露url和tls.certificateRef,没有单独基于Secret的认证字段。由于此时凭证会存放在envoy-gateway-configConfigMap中,请限制其读取权限,或者改用网络隔离 / ACL 受限的 Redis。完整 schema 请参见 Envoy Gateway rate-limit 文档。
Envoy Gateway 控制平面只会在启动时读取该引导配置,不会热重载,因此需要重启其 Deployment 以应用更改,然后确认专用的 envoy-ratelimit Deployment 运行正常:
每个 Envoy Gateway 使用一个 Redis 实例即可。任何可达的 Redis 都可以工作,但出于可用性和备份考虑,建议使用托管实例。
如果 Gateway 在启用限流后端之前已经运行,还需要重启其数据平面,以便代理加载限流服务:
在路由上捕获令牌用量
为 AIGatewayRoute 添加 llmRequestCosts,使网关把令牌计数写入 Envoy 动态元数据(过滤器之间用来通信的每请求临时空间)中,命名空间为 io.envoy.ai_gateway。下一步的限流过滤器会从该命名空间中读取。
-
metadataKey:写入io.envoy.ai_gateway下计数的键名。名称可自行选择;下面的BackendTrafficPolicy必须引用同一个字符串。 -
type:InputToken统计 prompt,OutputToken统计 completion,TotalToken为两者之和。若要使用自定义公式,可选CEL——例如,由于输出令牌更慢,可以将其计费为 3 倍:
应用并确认路由仍被接受(新字段不应破坏转换):
按身份定义令牌预算
绑定一个带有 Global 限流的 BackendTrafficPolicy。将请求成本设为 0,并将响应成本设为捕获到的令牌元数据,这样只有令牌会计入限制。使用 clientSelectors 按身份和模型范围限定预算。
x-user-id使用type: Distinct可为每个调用方提供独立计数器,从而实现按用户配额。若要按部门汇总到一个预算,可使用x-user-group;若要实现分层限制,也可以使用type: Exact匹配特定组(例如premium)。- 这里的
limit.requests会被解释为 令牌 预算,因为成本来自令牌元数据。使用200000令牌/小时,并且典型聊天调用大约消耗 1.5–2k 令牌,那么在触发限流之前,每个调用方大约可发出 ~100–130 次调用/小时。 cost.request.number: 0表示如果请求未到达上游(例如请求体格式错误),则不会消耗配额。若你也希望按调用次数进行预检限流,请将其设为1。cost.response.metadata.key必须与路由上声明的metadataKey一致。
验证
使用有效的身份令牌发起一轮短时间的请求,然后再使用另一个身份发起请求,确认只有第一个身份会被限流:
对于上面现实的 200000 令牌/小时预算,少量单词级请求消耗不到 1% 的配额,因此它们都会返回 200,你将不会看到 429。若要在短演示中观察到限流,请临时缩小预算——在 BackendTrafficPolicy 中将 limit.requests: 200 和 unit: Minute,重新应用,然后重启数据平面代理(kubectl rollout restart deployment -n envoy-gateway-system -l gateway.envoyproxy.io/owning-gateway-name=<gateway-name>)。演示成功后再恢复为真实预算。或者保留生产预算,发送几百个带大 prompt 和较长 max_tokens 的请求。
下面的验证使用 JWT 头 Authorization: Bearer。如果你改为配置了 API-key 认证(验证消费者身份 → “使用 API key 认证”),网关会从专用的 X-API-Key 头中读取凭证——将每个 -H "Authorization: Bearer $TOKEN_…" 替换为 -H "X-API-Key: $TOKEN_…"。
一轮耗尽 alice 配额的运行会输出类似 alice #1 -> 200 … alice #5 -> 429 … bob -> 200 的结果。若要直接在 Redis 中检查计数器,可搜索包含该身份值的键——Envoy Gateway 为每个计数器命名为 <gateway-namespace>/<gateway-name>/<listener>_<route>_..._<x-user-id-value>_..._<window-timestamp>,因此用户身份是最简单的过滤条件:
如果 Redis 不可达,Envoy 默认会 open:请求会在不计量的情况下通过,直到 Redis 恢复。请监控限流 pod 的日志(kubectl logs deploy/envoy-ratelimit -n envoy-gateway-system),并对其 Ready 条件进行告警,以免静默的配额失效未被发现。
了解更多
后续步骤
配置 计量令牌用量,以按租户报告消耗并进行分摊计费。