上周部署的客服机器人突然宕机,排查日志发现是某个用户连续发送了2000多次重复请求。这种突发流量不仅消耗了大量计算资源,更导致其他正常用户请求被阻塞。这让我意识到,在AI应用开发中,速率限制(Rate Limiting)不是可选项,而是保障服务稳定性的生命线。
LLM服务与传统API有显著差异:单次推理可能消耗数秒计算时间,GPU显存占用高,且token计费模式使得恶意请求可能造成巨额成本。合理的速率限制策略需要同时考虑:
Nginx的limit_req模块是最轻量级的解决方案。在/etc/nginx/conf.d/limit.conf中添加:
nginx复制limit_req_zone $binary_remote_addr zone=llm_zone:10m rate=5r/s;
server {
location /api/chat {
limit_req zone=llm_zone burst=20 nodelay;
proxy_pass http://llm_backend;
}
}
这种方案的优点是零代码侵入,但存在明显局限:
更灵活的方案是在FastAPI/Django等框架实现令牌桶算法。以下是Python示例:
python复制from fastapi import Request, HTTPException
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
app = FastAPI()
# 普通用户:5次/分钟
@app.post("/chat")
@limiter.limit("5/minute")
async def chat_endpoint(request: Request):
...
# VIP用户:30次/分钟
@app.post("/vip/chat")
@limiter.limit("30/minute")
async def vip_chat(request: Request):
...
关键参数需要根据实际负载测试确定:
AWS API Gateway提供开箱即用的速率限制:
json复制{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:123456789012:api123/prod/POST/chat",
"Condition": {
"IpAddress": {"aws:SourceIp": ["192.0.2.0/24"]},
"NumericLessThan": {"aws:MultiFactorAuthAge": "3600"}
}
}
]
}
优势在于与IAM体系深度集成,但跨云部署时可能产生厂商锁定问题。
对于高频重复内容请求,可采用SimHash算法生成文本指纹:
python复制import simhash
def generate_fingerprint(text: str, f=64, reg=8):
tokens = [text[i:i+reg] for i in range(0, len(text), reg)]
hashes = [hash(token) for token in tokens]
fingerprint = 0
for h in hashes:
fingerprint |= h
return fingerprint
duplicate_cache = {}
def check_duplicate(text):
fp = generate_fingerprint(text)
if fp in duplicate_cache:
raise HTTPException(429, "重复内容请求过于频繁")
duplicate_cache[fp] = time.time()
当检测到异常流量时,可触发验证挑战:
javascript复制// 前端验证示例
async function getChallenge() {
const res = await fetch('/api/challenge');
const { question, answer } = await res.json();
const userAnswer = prompt(question);
if (userAnswer !== answer) {
throw new Error('验证失败');
}
}
// 后端生成逻辑
questions = [
{"q": "3+5的后两位字母是?", "a": "ht"},
{"q": "苹果的拼音首字母?", "a": "p"}
]
结合token消耗动态调整限制:
python复制from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("gpt-3.5-turbo")
def calculate_cost(text):
tokens = tokenizer(text)["input_ids"]
return len(tokens)
@app.post("/chat")
@limiter.limit("1000 tokens/minute") # 改为token计数
async def chat_endpoint(request: Request, prompt: str):
cost = calculate_cost(prompt)
request.state.token_cost = cost # 在limiter中消费token配额
...
Prometheus监控应包含关键指标:
yaml复制metrics:
- name: llm_requests_total
type: counter
labels: [endpoint, user_type]
- name: llm_tokens_consumed
type: histogram
buckets: [100, 500, 1000, 5000]
- name: rate_limit_hits
type: counter
labels: [rule_name]
根据负载情况动态降级:
python复制def dynamic_rate_limit():
cpu = get_cpu_usage()
if cpu > 80:
return "2/minute"
elif cpu > 60:
return "5/minute"
else:
return "10/minute"
@app.post("/chat")
@limiter.limit(dynamic_rate_limit)
async def chat_endpoint(request: Request):
...
结合异常检测自动封禁:
python复制from datetime import datetime, timedelta
ip_blacklist = {}
def check_blacklist(ip):
if ip in ip_blacklist:
if datetime.now() < ip_blacklist[ip]:
raise HTTPException(403, "IP暂时封禁")
else:
del ip_blacklist[ip]
def record_abuse(ip):
ip_blacklist[ip] = datetime.now() + timedelta(hours=1)
不要依赖客户端计时
浏览器端setInterval控制的请求间隔可被开发者工具绕过,所有限制必须服务端实现
分布式环境一致性挑战
多实例部署时需使用Redis等集中式存储:
python复制from redis import Redis
limiter = Limiter(storage=Redis(host="redis"))
合理设置burst值
突发容量应略大于正常用户的连续操作需求,例如:
灰度发布策略
新规则上线前先对10%流量生效,观察:
移动端特殊处理
App用户可能因网络切换导致IP变化,应优先使用user_id而非IP限制
最近一个电商客户案例中,通过实施分级速率限制(游客1r/s、会员5r/s、VIP20r/s),在流量增长300%的情况下,GPU服务器成本反而降低40%,同时99分位响应时间从7秒降至1.3秒。这印证了良好的限流策略既能保护资源,也能提升整体服务质量。