跳到主要内容

限流控制

概述

限流控制(Rate Limiting)是 LLM Gateway 的重要安全和资源管理功能,通过对 API 请求进行流量控制和配额限制,保护系统资源不被滥用,确保服务稳定性和公平性。

🛡️
防止滥用
限制单个用户或 Token 的请求频率,防止恶意调用
🖥️
资源保护
避免系统过载,确保所有用户获得稳定服务
💰
成本控制
通过配额限制控制 LLM API 调用成本
📚
多层限流
支持全局、渠道、用户、Token 多个层级的限流

限流层级

LLM Gateway 支持多层级的限流控制,从全局到用户级别,提供灵活的流量管理:

限流层级架构

全局限流
├── 渠道限流
│ ├── 渠道 A: 100 req/min
│ ├── 渠道 B: 200 req/min
│ └── 渠道 C: 150 req/min

├── IP 限流
│ └── 单 IP: 60 req/min

├── Token 限流
│ ├── Token 1: 1000 req/day, 10000 tokens/day
│ ├── Token 2: 5000 req/day, 50000 tokens/day
│ └── Token 3: 无限制(VIP)

└── 用户限流
├── 普通用户: 100 req/hour
├── 高级用户: 1000 req/hour
└── 管理员: 无限制

层级说明

全局限流

作用范围: 整个系统

限制对象:

  • 总请求速率(req/s)
  • 总并发连接数
  • 系统总配额

适用场景:

  • 保护后端系统不过载
  • 控制整体资源消耗
  • 防御 DDoS 攻击

配置示例:

{
"global_rate_limit": {
"requests_per_second": 1000,
"max_concurrent": 500,
"burst": 1500
}
}
渠道限流

作用范围: 单个 LLM 提供商渠道

限制对象:

  • 渠道请求速率
  • 渠道并发连接数
  • 渠道配额(tokens)

适用场景:

  • 遵守提供商的 API 速率限制
  • 避免单个渠道过载
  • 控制单个渠道的成本

配置示例:

{
"channel_id": 1,
"rate_limit": 60, // 60 req/min
"max_concurrent": 20, // 20 并发
"quota": 1000000, // 1M tokens
"quota_period": "month" // 月度配额
}
IP 限流

作用范围: 单个客户端 IP 地址

限制对象:

  • IP 请求速率
  • IP 并发连接数

适用场景:

  • 防止单个 IP 滥用
  • 防御爬虫和攻击
  • 公平分配资源

配置示例:

{
"ip_rate_limit": {
"requests_per_minute": 60,
"max_concurrent": 5,
"whitelist": ["1.2.3.4", "5.6.7.8"],
"blacklist": ["9.9.9.9"]
}
}
Token 限流

作用范围: 单个 API Token

限制对象:

  • Token 请求速率
  • Token 配额(tokens)
  • Token 请求总数

适用场景:

  • 为不同客户分配不同配额
  • 实现订阅套餐
  • 精确的成本控制

配置示例:

{
"token": "sk-abc123...",
"rate_limit": 100, // 100 req/hour
"quota": 100000, // 100K tokens
"quota_period": "day", // 每日配额
"total_quota": 1000000, // 总配额 1M tokens
"unlimited": false
}
用户限流

作用范围: 单个用户账户

限制对象:

  • 用户请求速率
  • 用户配额
  • 用户下所有 Token 的总配额

适用场景:

  • 用户级别的配额管理
  • 订阅计划实现
  • 多 Token 统一管理

配置示例:

{
"user_id": 1,
"rate_limit": 1000, // 1000 req/hour
"quota": 1000000, // 1M tokens/month
"quota_period": "month",
"tier": "premium" // 用户等级
}

限流优先级

当多个层级同时配置限流时,按以下优先级执行:

  1. 全局限流: 最高优先级,所有请求都受限
  2. IP 限流: 黑名单 IP 直接拒绝,白名单 IP 跳过部分限制
  3. Token 限流: Token 级别的速率和配额限制
  4. 用户限流: 用户级别的总配额限制
  5. 渠道限流: 最后检查渠道可用配额
信息

请求需要通过所有层级的限流检查才能被处理。任何一层超限都会导致请求被拒绝。

配置指南

全局限流配置

1

进入系统设置

登录管理后台,导航到 系统设置 > 限流控制。

限流控制设置页面
2

配置全局速率限制

设置系统整体的请求速率限制:

  • 每秒请求数(RPS): 系统总 QPS 上限
  • 突发流量: 允许短时间内超过速率的请求数
  • 最大并发: 系统最大并发请求数
全局速率配置
3

配置 IP 限流

设置单个 IP 的限制:

  • 每分钟请求数: 单 IP 速率限制
  • 最大并发: 单 IP 最大并发连接
  • IP 白名单: 不受限制的 IP 列表
  • IP 黑名单: 禁止访问的 IP 列表
IP 限流配置
4

保存配置

点击"保存"按钮应用配置,立即生效。

渠道限流配置

为每个渠道独立配置限流:

1

编辑渠道

在渠道管理页面,点击目标渠道的"编辑"按钮。

渠道列表
2

配置速率限制

在"限流设置"部分:

  • 每分钟请求数: 该渠道的速率限制(遵守提供商要求)
  • 最大并发: 同时处理的最大请求数

示例:

OpenAI GPT-4:
- 速率限制: 3500 req/min
- 最大并发: 50

OpenAI GPT-3.5:
- 速率限制: 10000 req/min
- 最大并发: 100
渠道速率限制配置
3

配置配额限制

设置渠道的 token 配额:

  • 配额总量: 允许使用的 token 数量
  • 配额周期: 小时/天/月
  • 已用配额: 当前已使用量(只读)
  • 重置日期: 配额重置时间
渠道配额配置
4

保存并测试

保存配置后,发送测试请求验证限流是否生效。

Token 限流配置

为不同的 API Token 设置不同的限额:

1

创建或编辑 Token

在 Token 管理页面,创建新 Token 或编辑现有 Token。

Token 管理页面
2

设置速率限制

配置 Token 的请求速率:

  • 每小时请求数: Token 每小时最大请求数
  • 每日请求数: Token 每日最大请求数
  • 不限速: 勾选后取消速率限制(仅管理员)
Token 速率限制
3

设置配额

配置 Token 的 token 配额:

  • 每日配额: 每天可用的 tokens
  • 每月配额: 每月可用的 tokens
  • 总配额: Token 生命周期内的总 tokens
  • 无限配额: 勾选后取消配额限制

套餐示例:

套餐请求数/天配额/月总配额
免费100100K1M
基础10001M无限
专业1000010M无限
企业无限无限无限
Token 配额设置
4

配置高级选项

可选的高级配置:

  • 配额重置日期: 自定义配额重置时间
  • 共享配额: 多个 Token 共享配额池
  • 优先级: 配额不足时的优先级
  • 超额处理: 超额后降级或拒绝
Token 高级配置
5

保存并通知

保存 Token 配置,系统会自动通知 Token 持有者。

用户限流配置

为用户账户设置限流:

1

编辑用户

在用户管理页面,选择目标用户进行编辑。

用户管理页面
2

设置用户等级

选择用户等级,不同等级有不同的限流策略:

  • 普通用户: 基础限流
  • 高级用户: 较高限额
  • VIP 用户: 大幅提升限额
  • 管理员: 不受限制
用户等级设置
3

配置用户配额

设置用户级别的总配额:

  • 月度配额: 用户每月总 token 配额
  • 包含所有 Token: 该用户下所有 Token 共享此配额
  • 已用配额: 当前月度使用量
用户配额配置
4

保存配置

保存后,用户下的所有 Token 都受此配额限制。

限流算法

令牌桶算法 (Token Bucket)

LLM Gateway 使用令牌桶算法实现限流,支持突发流量:

工作原理:

1

初始化桶

创建一个容量为 N 的令牌桶,初始时桶是满的。

桶容量: 100 个令牌
当前令牌: 100
2

定期补充

以固定速率(如 10 个/秒)向桶中添加令牌,桶满时停止。

每秒补充: 10 个令牌
补充周期: 100ms
每次补充: 1 个令牌
3

消费令牌

每个请求尝试从桶中取 1 个令牌:

  • 如果桶中有令牌,取走 1 个,请求通过
  • 如果桶空了,请求被拒绝
请求到达 → 桶中有令牌?
├── 是: 取走 1 个,放行请求
└── 否: 拒绝请求,返回 429
4

支持突发

因为桶有容量,可以累积令牌,支持短时间的突发流量。

桶容量 100,速率 10/s:
- 可以瞬间处理 100 个请求
- 然后降级到 10 req/s 的稳定速率
令牌桶算法示意图

配置参数:

参数说明示例值
capacity桶容量(最大突发)100
rate补充速率(req/s)10
period统计周期1 秒

滑动窗口算法 (Sliding Window)

用于更精确的速率限制,避免边界问题:

工作原理:

时间线: |-------|-------|-------|-------|
t-3 t-2 t-1 t t+1

窗口大小: 1 分钟
限制: 60 req/min

当前时刻 t:
- 统计过去 60 秒内的请求数
- 如果 < 60,允许请求
- 如果 >= 60,拒绝请求

优势:

  • 更平滑的限流
  • 避免固定窗口的边界突发
  • 更精确的速率控制

实现:

// 伪代码
func slidingWindow(key string, limit int, window time.Duration) bool {
now := time.Now()
windowStart := now.Add(-window)

// 清除窗口外的记录
redis.ZREMRANGEBYSCORE(key, 0, windowStart.Unix())

// 统计窗口内的请求数
count := redis.ZCARD(key)

if count < limit {
// 记录当前请求
redis.ZADD(key, now.Unix(), now.UnixNano())
redis.EXPIRE(key, window)
return true
}

return false
}

配额管理

配额类型

定义: 限制 LLM API 调用的 token 数量

计量方式:

配额消耗 = 输入 tokens + 输出 tokens

应用场景:

  • 控制 API 调用成本
  • 实现订阅套餐
  • 防止滥用

示例:

{
"token_quota": {
"daily": 10000, // 每日 1 万 tokens
"monthly": 300000, // 每月 30 万 tokens
"total": 10000000, // 总计 1000 万 tokens
"used_daily": 5234, // 今日已用
"used_monthly": 156789,
"used_total": 2345678
}
}

配额周期

支持多种配额周期:

周期重置时间适用场景
小时每小时整点短期速率控制
每日 00:00常规配额管理
每周一 00:00周度套餐
每月 1 日 00:00订阅计费
自定义指定日期时间特殊需求
永久不重置总量控制

配额重置

自动重置

配额到期自动重置为初始值:

配额: 10000 tokens/天

2025-10-18 00:00:00:
- 已用配额: 8734 → 0
- 可用配额: 1266 → 10000

系统会在配额重置时:

  • 记录上周期的使用统计
  • 发送使用报告(如果启用)
  • 清零使用量计数器
手动重置

管理员可以手动重置配额:

Web 界面:

  1. 进入 Token 或用户管理页面
  2. 点击"重置配额"按钮
  3. 确认操作

API:

curl -X POST https://your-gateway.com/api/token/1/quota/reset \
-H "Authorization: Bearer ADMIN_TOKEN"
配额追加

临时增加配额,不改变周期配置:

场景: 用户临时需要更多配额

操作:

curl -X POST https://your-gateway.com/api/token/1/quota/add \
-H "Authorization: Bearer ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"amount": 50000,
"reason": "特殊活动追加配额"
}'

效果:

  • 配额立即增加 50000
  • 不影响下次重置的基础配额
  • 记录操作日志

配额监控

在管理后台查看所有 Token 和用户的配额使用情况:

  • 总体配额使用率: 饼图显示
  • Top 消费者: 按使用量排序
  • 配额告警: 接近上限的 Token
  • 配额趋势: 每日/每周使用趋势
配额仪表板

错误处理

限流错误响应

当请求被限流拒绝时,返回标准的 HTTP 429 错误:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1634567890
Retry-After: 60

{
"error": {
"message": "Rate limit exceeded. Please try again in 60 seconds.",
"type": "rate_limit_error",
"code": "rate_limit_exceeded",
"param": null
}
}

响应头说明

响应头说明示例值
X-RateLimit-Limit速率限制(单位时间内最大请求数)100
X-RateLimit-Remaining剩余配额23
X-RateLimit-Reset配额重置时间戳(Unix)1634567890
X-Quota-LimitToken 配额限制100000
X-Quota-Remaining剩余 Token 配额45678
X-Quota-Used已用 Token 配额54322
Retry-After建议重试间隔(秒)60

客户端处理

客户端应正确处理限流错误:

Python
import openai
import time

def call_with_retry(max_retries=3):
for attempt in range(max_retries):
try:
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "Hello"}]
)
return response
except openai.error.RateLimitError as e:
if attempt < max_retries - 1:
# 从响应头获取重试时间
retry_after = int(e.headers.get('Retry-After', 60))
print(f"Rate limited. Retrying in {retry_after}s...")
time.sleep(retry_after)
else:
raise
JavaScript
async function callWithRetry(maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await openai.chat.completions.create({
model: 'gpt-3.5-turbo',
messages: [{ role: 'user', content: 'Hello' }],
});
return response;
} catch (error) {
if (error.status === 429 && attempt < maxRetries - 1) {
const retryAfter = parseInt(error.headers['retry-after'] || '60');
console.log(`Rate limited. Retrying in ${retryAfter}s...`);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
} else {
throw error;
}
}
}
}
Bash with jq
#!/bin/bash

call_api() {
response=$(curl -s -w "\n%{http_code}" \
-X POST https://your-gateway.com/v1/chat/completions \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-3.5-turbo","messages":[{"role":"user","content":"Hello"}]}')

http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')

if [ "$http_code" = "429" ]; then
retry_after=$(echo "$body" | jq -r '.error.retry_after // 60')
echo "Rate limited. Retrying in ${retry_after}s..."
sleep "$retry_after"
call_api # 递归重试
else
echo "$body"
fi
}

call_api

配额不足处理

配额告警

当配额使用达到阈值时,系统会发送告警:

邮件通知示例:

主题: [LLM Gateway] 配额告警 - Token ABC123

您的 Token (ABC123) 配额使用已达 85%:

- 每日配额: 10,000 tokens
- 已使用: 8,500 tokens
- 剩余: 1,500 tokens
- 预计耗尽时间: 2 小时

建议:
1. 优化 API 调用,减少 token 使用
2. 升级套餐以获得更多配额
3. 等待配额重置(今日 23:59:59)

查看详情: https://your-gateway.com/tokens/ABC123
自动降级

配额不足时自动降级到低成本模型:

{
"auto_downgrade": {
"enabled": true,
"rules": [
{
"threshold": 0.9, // 90% 时触发
"from_model": "gpt-4",
"to_model": "gpt-3.5-turbo",
"notify_user": true
}
]
}
}

响应头会标识降级:

X-Model-Downgraded: true
X-Original-Model: gpt-4
X-Actual-Model: gpt-3.5-turbo
X-Downgrade-Reason: quota_limit
配额用尽处理

配额完全用尽后的处理策略:

策略 1: 拒绝请求(默认)

HTTP/1.1 429 Too Many Requests

{
"error": {
"message": "Quota exceeded. Please upgrade your plan or wait for quota reset.",
"type": "quota_exceeded",
"code": "insufficient_quota"
}
}

策略 2: 降级到免费模型

  • 自动使用免费/低成本渠道
  • 标记降级响应

策略 3: 超额扣款

  • 允许超额使用
  • 按超额部分额外计费
  • 需要配置超额费率

监控和分析

限流监控

实时查看系统限流状态:

  • 当前 QPS
  • 限流拒绝率
  • 各层级限流触发次数
  • 热点 IP / Token
限流实时监控

配额分析

📊
使用分布
按用户、Token、模型、渠道统计配额使用分布
💲
成本分析
分析配额使用的成本构成和优化空间
⚠️
异常检测
识别异常的配额使用模式(突增、异常高频等)
🔮
预测分析
基于历史数据预测配额耗尽时间
配额分析仪表板

最佳实践

限流策略建议

📚
分层设计
从全局到用户逐层设置限流,每层关注不同目标
📏
留有余量
限流值留 20-30% 余量应对突发流量
↕️
渐进调整
根据实际负载逐步调整,避免一步到位
🔔
监控告警
设置合理的告警阈值,及时发现问题

配额规划

  1. 评估需求:

    • 统计历史 API 调用量
    • 预估业务增长
    • 考虑峰值和平均值
    • 分析不同用户群的使用模式
  2. 设计套餐:

    免费套餐:
    - 100 req/day
    - 10K tokens/day
    - 适合个人试用

    基础套餐 ($10/月):
    - 1000 req/day
    - 100K tokens/day
    - 适合小型项目

    专业套餐 ($50/月):
    - 10000 req/day
    - 1M tokens/day
    - 适合中型应用

    企业套餐(定制):
    - 无限请求
    - 按 token 计费
    - 适合大规模应用
  3. 弹性配置:

    • 支持临时提升配额
    • 提供配额追加服务
    • 考虑季节性波动
  4. 成本控制:

    • 设置成本上限告警
    • 提供成本预估工具
    • 优化 token 使用效率

性能优化

使用 Redis 存储限流状态

高性能的限流实现依赖 Redis:

优势:

  • 内存存储,极低延迟(< 1ms)
  • 原子操作,保证准确性
  • 支持 TTL,自动清理过期数据
  • 支持集群,水平扩展

配置:

# .env
REDIS_CONN_STRING=redis://localhost:6379
RATE_LIMIT_REDIS_DB=1 # 使用独立的 DB
优化限流检查逻辑

减少限流检查的性能开销:

  • 批量检查: 一次检查多个限流层级
  • 短路优化: 先检查最可能超限的层级
  • 缓存结果: 短时间内缓存检查结果
  • 异步记录: 异步更新使用统计
// 伪代码
func checkRateLimit(req) bool {
// 先检查 IP 黑名单(最快拒绝)
if isBlacklisted(req.IP) {
return false
}

// 再检查全局限流(影响所有请求)
if !checkGlobalLimit() {
return false
}

// 最后检查 Token 限流(最精细)
return checkTokenLimit(req.Token)
}
分布式限流

多节点部署时使用分布式限流:

挑战: 多个节点独立计数会导致限流不准确

解决方案:

  • 使用 Redis 作为中央计数器
  • 使用分布式令牌桶算法
  • 定期同步各节点状态
分布式限流架构

安全建议

注意

限流是安全防护的重要手段,但不是唯一手段:

  • 组合使用: 限流 + 防火墙 + WAF + 验证码
  • 动态调整: 检测到攻击时自动收紧限流
  • IP 黑名单: 自动封禁恶意 IP
  • 异常检测: 识别异常使用模式并告警
  • 日志审计: 记录所有限流事件供事后分析

常见问题

为什么会出现 429 错误?

可能原因:

  1. 超过了 Token 的速率限制
  2. 配额已用完
  3. IP 请求过于频繁
  4. 渠道达到并发上限
  5. 系统全局限流

排查步骤:

  1. 检查响应头的限流信息
  2. 查看 Token 或用户的配额使用情况
  3. 确认请求频率是否在限制范围内
  4. 联系管理员查看详细日志
如何临时提升配额?

管理员操作:

  1. 进入 Token 或用户管理页面
  2. 点击"追加配额"按钮
  3. 输入追加数量和原因
  4. 确认操作

或通过 API:

curl -X POST /api/token/{id}/quota/add \
-d '{"amount": 50000}'
限流会影响性能吗?

影响: 非常小,通常 < 1ms

原因:

  • 使用 Redis 内存存储,极快
  • 限流检查是简单的计数操作
  • 异步更新统计数据

优化:

  • 确保 Redis 性能良好
  • 使用 Redis 连接池
  • 避免复杂的限流逻辑
如何设置合理的限流值?

步骤:

  1. 收集数据: 统计当前请求速率和配额使用
  2. 分析峰值: 识别峰值流量和平均流量
  3. 留有余量: 限流值 = 峰值 × 1.2 - 1.5
  4. 分级设置: 不同用户等级设置不同限流
  5. 持续调优: 根据实际运行情况调整

参考值:

  • 免费用户: 峰值的 1.2 倍
  • 付费用户: 峰值的 1.5 倍
  • 企业用户: 峰值的 2 倍
配额重置时间可以自定义吗?

可以。在 Token 或用户配置中:

  • 标准重置: 每日 00:00, 每月 1 日 00:00
  • 自定义重置: 指定具体日期和时间
  • 周期偏移: 从创建时间起算周期

示例:

{
"quota_reset": {
"type": "custom",
"reset_at": "2025-11-01 00:00:00",
"period": "month"
}
}
如何防止恶意用户绕过限流?

防护措施:

  1. 多层限流: 同时限制 IP、Token、用户
  2. 设备指纹: 识别同一设备的多次请求
  3. 行为分析: 检测异常使用模式
  4. 验证码: 可疑流量要求验证码
  5. IP 封禁: 自动封禁恶意 IP
  6. Token 吊销: 立即吊销被滥用的 Token
多层防护架构

相关页面