首页/数据/数据库速查/计数器限流(INCR + EXPIRE)
Redis 运维与场景124 条

计数器限流(INCR + EXPIRE)

最简限流实现:INCR 计数 + EXPIRE 窗口过期;窗口键(如按分钟/用户)首次请求设置过期时间,超过阈值直接拒绝。

数据库速查数据更新于 2026-10-13

计数器限流是什么

用 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 加接口)各算各的键:维度组合越细,键数量越多,要评估内存与过期清理成本。
限流被绕过或失效会造成真实损失:一旦发现计数键永不过期或阈值取自配置中心缓存,要按故障处理。

易错点

  • INCR 之后 EXPIRE 没执行成功(进程崩溃或网络断开):计数键永不过期,用户被永久限流
  • 窗口键用当前时间字符串拼接但服务器时钟回拨:旧窗口复活,计数错乱
  • 依赖两步命令而不做原子化:并发首次请求时多个客户端同时判断「键不存在」,TTL 被反复覆盖
  • 把所有维度塞进一个键:无法按用户或接口分档限流,一个异常来源会拖垮全部请求

数据来源与参考

  • Redis 官方文档: INCR
  • 限流模式实践

相关工具

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌