限流控制
概述
限流控制(Rate Limiting)是 LLM Gateway 的重要安全和资源管理功能,通过对 API 请求进行流量控制和配额限制,保护系统资源不被滥用,确保服务稳定性和公平性。
限流层级
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" // 用户等级
}
限流优先级
当多个层级同时配置限流时,按以下优先级执行:
- 全局限流: 最高优先级,所有请求都受限
- IP 限流: 黑名单 IP 直接拒绝,白名单 IP 跳过部分限制
- Token 限流: Token 级别的速率和配额限制
- 用户限流: 用户级别的总配额限制
- 渠道限流: 最后检查渠道可用配额
请求需要通过所有层级的限流检查才能被处理。任何一层超限都会导致请求被拒绝。
配置指南
全局限流配置
进入系统设置
登录管理后台,导航到 系统设置 > 限流控制。
配置全局速率限制
设置系统整体的请求速率限制:
- 每秒请求数(RPS): 系统总 QPS 上限
- 突发流量: 允许短时间内超过速率的请求数
- 最大并发: 系统最大并发请求数
配置 IP 限流
设置单个 IP 的限制:
- 每分钟请求数: 单 IP 速率限制
- 最大并发: 单 IP 最大并发连接
- IP 白名单: 不受限制的 IP 列表
- IP 黑名单: 禁止访问的 IP 列表
保存配置
点击"保存"按钮应用配置,立即生效。
渠道限流配置
为每个渠道独立配置限流:
编辑渠道
在渠道管理页面,点击目标渠道的"编辑"按钮。
配置速率限制
在"限流设置"部分:
- 每分钟请求数: 该渠道的速率限制(遵守提供商要求)
- 最大并发: 同时处理的最大请求数
示例:
OpenAI GPT-4:
- 速率限制: 3500 req/min
- 最大并发: 50
OpenAI GPT-3.5:
- 速率限制: 10000 req/min
- 最大并发: 100
配置配额限制
设置渠道的 token 配额:
- 配额总量: 允许使用的 token 数量
- 配额周期: 小时/天/月
- 已用配额: 当前已使用量(只读)
- 重置日期: 配额重置时间
保存并测试
保存配置后,发送测试请求验证限流是否生效。
Token 限流配置
为不同的 API Token 设置不同的限额:
创建或编辑 Token
在 Token 管理页面,创建新 Token 或编辑现有 Token。
设置速率限制
配置 Token 的请求速率:
- 每小时请求数: Token 每小时最大请求数
- 每日请求数: Token 每日最大请求数
- 不限速: 勾选后取消速率限制(仅管理员)
设置配额
配置 Token 的 token 配额:
- 每日配额: 每天可用的 tokens
- 每月配额: 每月可用的 tokens
- 总配 额: Token 生命周期内的总 tokens
- 无限配额: 勾选后取消配额限制
套餐示例:
| 套餐 | 请求数/天 | 配额/月 | 总配额 |
|---|---|---|---|
| 免费 | 100 | 100K | 1M |
| 基础 | 1000 | 1M | 无限 |
| 专业 | 10000 | 10M | 无限 |
| 企业 | 无限 | 无限 | 无限 |
配置高级选项
可选的高级配置:
- 配额重置日期: 自定义配额重置时间
- 共享配额: 多个 Token 共享配额池
- 优先级: 配额不足时的优先级
- 超额处理: 超额后降级或拒绝
保存并通知
保存 Token 配置,系统会自动通知 Token 持有者。
用户限流配置
为用户账户设置限流:
编辑用户
在用户管理页面,选择目标用户进行编辑。
设置用户等级
选择用户等级,不同等级有不同的限流策略:
- 普通用户: 基础限流
- 高级用户: 较高限额
- VIP 用户: 大幅提升限额
- 管理员: 不受限制
配置用户配额
设置用户级别的总配额:
- 月度配额: 用户每月总 token 配额
- 包含所有 Token: 该用户下所有 Token 共享此配额
- 已用配额: 当前月度使用量
保存配置
保存后,用户下的所有 Token 都受此配额限制。
限流算法
令牌桶算法 (Token Bucket)
LLM Gateway 使用令牌桶算法实现限流,支持突发流量:
工作原理:
初始化桶
创建一个容量为 N 的令牌桶,初始时桶是满的。
桶容量: 100 个令牌
当前令牌: 100定期补充
以固定速率(如 10 个/秒)向桶中添加令牌,桶满时停止。
每秒补充: 10 个令牌
补充周期: 100ms
每次补充: 1 个令牌消费令牌
每个请求尝试从桶中取 1 个令牌:
- 如果桶中有令牌,取走 1 个,请求通过
- 如果桶空了,请求被拒绝
请求到达 → 桶中有令牌?
├── 是: 取走 1 个,放行请求
└── 否: 拒绝请求,返回 429支持突发
因为桶有容量,可以累积令牌,支持短时间的突发流量。
桶容量 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
}
配额管理
配额类型
- Token 配额
- 请求配额
- 成本配额
定义: 限制 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
}
}
定义: 限制 API 请求的次数
计量方式:
配额消耗 = 1 次请求
应用场景:
- 防止频繁调用
- 简单的限流
- 公平分配资源
示例:
{
"request_quota": {
"hourly": 100, // 每小时 100 次
"daily": 1000, // 每日 1000 次
"used_hourly": 67,
"used_daily": 543
}
}
定义: 限制 API 调用的金额
计量方式:
配额消耗 = 输入 tokens × 输入单价 + 输出 tokens × 输出单价
应用场景:
- 精确成本控制
- 预算管理
- 防止超支
示例:
{
"cost_quota": {
"monthly_usd": 100.00, // 月度预算 $100
"used_usd": 67.89, // 已用 $67.89
"remaining_usd": 32.11, // 剩余 $32.11
"alert_threshold": 0.8 // 80% 时告警
}
}
配额周期
支持多种配额周期:
| 周期 | 重置时间 | 适用场景 |
|---|---|---|
| 小时 | 每小时整点 | 短期速率控制 |
| 天 | 每日 00:00 | 常规配额管理 |
| 周 | 每周一 00:00 | 周度套餐 |
| 月 | 每月 1 日 00:00 | 订阅计费 |
| 自定义 | 指定日期时间 | 特殊需求 |
| 永久 | 不重置 | 总量控制 |
配额重置
自动重置
配额到期自动重置为初始值:
配额: 10000 tokens/天
2025-10-18 00:00:00:
- 已用配额: 8734 → 0
- 可用配额: 1266 → 10000
系统会在配额重置时:
- 记录上周期的使用统计
- 发送使用报告(如果启用)
- 清零使用量计数器
手动重置
管理员可以手动重置配额:
Web 界面:
- 进入 Token 或用户管理页面
- 点击"重置配额"按钮
- 确认操作
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
- 配额趋势: 每日/每周使用趋势
配置配额告警规则:
{
"alerts": [
{
"threshold": 0.8, // 80% 时告警
"notification": "email", // 邮件通知
"recipients": ["admin@example.com"]
},
{
"threshold": 0.95, // 95% 时告警
"notification": "webhook",
"url": "https://alert.example.com/hook"
}
]
}
定期生成配额使用报告:
- 每日报告: 汇总当天使用情况
- 每周报告: 对比上周,识别趋势
- 每月报告: 月度账单和使用分析
报告内容:
- 总请求数和 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-Limit | Token 配额限制 | 100000 |
| X-Quota-Remaining | 剩余 Token 配额 | 45678 |
| X-Quota-Used | 已用 Token 配额 | 54322 |
| Retry-After | 建议重试间隔(秒) | 60 |
客户端处理
客户端应正确处理限流错误:
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
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;
}
}
}
}
#!/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
查看历史限流数据:
- 限流拒绝次数趋势
- 配额使用趋势
- 峰值流量分析
- 异常流量检测
详细的限流事件日志:
[2025-10-18 10:30:15] [RATE_LIMIT] IP 1.2.3.4 exceeded rate limit (120/100 req/min)
[2025-10-18 10:30:16] [RATE_LIMIT] Token abc123 exceeded quota (10500/10000 tokens/day)
[2025-10-18 10:30:17] [RATE_LIMIT] Channel 1 concurrent limit reached (50/50)
可以按以下维度筛选:
- 时间范围
- 限流类型
- IP / Token / 渠道
- 拒绝原因
配额分析
最佳实践
限流策略建议
配额规划
-
评估需求:
- 统计历史 API 调用量
- 预估业务增长
- 考虑峰值和平均值
- 分析不同用户群的使用模式
-
设计套餐:
免费套餐:
- 100 req/day
- 10K tokens/day
- 适合个人试用
基础套餐 ($10/月):
- 1000 req/day
- 100K tokens/day
- 适合小型项目
专业套餐 ($50/月):
- 10000 req/day
- 1M tokens/day
- 适合中型应用
企业 套餐(定制):
- 无限请求
- 按 token 计费
- 适合大规模应用 -
弹性配置:
- 支持临时提升配额
- 提供配额追加服务
- 考虑季节性波动
-
成本控制:
- 设置成本上限告警
- 提供成本预估工具
- 优化 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
- 异常检测: 识别异常使用模式并告警
- 日志审计: 记录所有限流事件供事后分析