计数器限流是什么
用 Redis 的原子自增做限流:把「用户或接口加时间窗口」拼成键名,每次请求 INCR 一次,第一次请求时给键设置过期时间,返回值超过阈值就拒绝。原理简单、成本极低,是接口防刷与配额控制的入门方案。
基本信息
| 核心命令 | INCR / EXPIRE,或用 SET key 0 NX EX 秒 初始化 |
|---|---|
| 键设计 | 业务前缀加用户或接口加时间粒度,如 rate:user1001:202610121530 |
| 阈值 | 按接口、用户、租户分别设定,不要全局一个数 |
| 原子性 | INCR 本身原子;INCR 与 EXPIRE 两步之间要用 Lua 或 SET NX 兜住 |
| 窗口类型 | 固定窗口实现最简单,但存在跨窗口边界效应 |
典型使用场景
- 短信、邮件验证码发送频率限制:单手机号每分钟最多几条,防刷防轰炸
- 登录与注册接口防暴力破解:同 IP 或同账号按分钟计数,超限直接拒绝
- 开放接口配额:按 AppKey 限制每分钟调用量,超限返回限流错误码
- 活动抢购前置削峰:在真正进入库存逻辑前先挡掉超量请求
- 爬虫与异常流量识别:把单位时间计数接入告警,作为风控信号
固定窗口限流
固定窗口限流
SET rate:user1001:202610121530 0 NX EX 60 # 首次请求初始化并设置窗口
INCR rate:user1001:202610121530 # 每次请求自增,返回值即当前计数
# 返回值大于 100 就拒绝(阈值按业务定)
GET rate:user1001:202610121530
TTL rate:user1001:202610121530 # 确认窗口剩余秒数
EXPIRE rate:user1001:202610121530 60 NX # 7.0 起可只给没有过期时间的键补 TTL键设计与参数
| 要素 | 取值建议 | 说明 |
|---|---|---|
| 维度 | 用户、IP、接口、租户 | 维度选错会出现「一人拖垮全站」或限不住 |
| 时间粒度 | 分钟或小时或天 | 粒度写进键名,不同粒度用不同键 |
| 过期秒数 | 等于窗口长度 | 过期时间短于窗口会提前放行 |
| 阈值 | 按接口重要性分级 | 登录类收紧,查询类放宽 |
固定窗口的边界问题:第 59 秒打满 100 次,第 61 秒又打满 100 次,实际两秒内放过了 200 次请求。要求严格时改用 ZSet 滑动窗口或 Lua 令牌桶。
多个限流维度(用户加接口、IP 加接口)各算各的键:维度组合越细,键数量越多,要评估内存与过期清理成本。
限流被绕过或失效会造成真实损失:一旦发现计数键永不过期或阈值取自配置中心缓存,要按故障处理。