限流不能识别单key击穿,仅按IP或接口粗粒度限速,无法阻止同一热点key的并发请求打库,故对击穿只是弱防护;真正防护需在业务层加锁或逻辑过期。

限流本身不防击穿,但能缓解击穿引发的DB雪崩;真正要防击穿,得在缓存层加锁或逻辑过期,限流只是兜底手段。
为什么网关限流对缓存击穿只是“弱防护”
缓存击穿是热点key过期瞬间,大量请求穿透Redis直打DB;而网关限流作用在请求入口,它按IP、用户ID或API路径做速率控制,但无法识别“这个请求是不是正在击穿某个key”。比如1000个请求同时查 product:10086,哪怕网关限流设为500QPS,剩下的500个仍会全打到DB——因为它们都合法、都命中同一接口,限流策略根本没区分语义。
常见错误现象:监控看到网关限流日志几乎不触发,但DB CPU飙升、慢查询暴增;说明限流没拦住击穿流量,只拦住了泛滥的无效请求。
- 网关限流维度(如
user_id或/api/v1/product)和缓存key粒度(如product:10086)天然不一致 - 击穿是“单key高并发”,限流通常是“多key粗粒度”,二者匹配不上
- 若强行用网关限流压制单key访问(比如对
/product/{id}全局限5QPS),会误伤正常请求,体验断崖式下跌
Redis限流该放在哪一层才真正帮上忙
必须下沉到业务服务内部,和缓存读写逻辑耦合。比如用户服务在处理 GET /user/123 时,先查Redis,发现 user:123 过期或不存在,此时不是直接查DB,而是用 SET user:123:lock "token" EX 30 NX 尝试加锁;没抢到锁的请求,可配合轻量级限流(如每秒最多放行2个等待线程)避免自旋耗尽CPU。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
实操建议:
- 不要依赖网关统一限流来防击穿,它离数据层太远,响应滞后且颗粒度太粗
- 在业务服务里用Redis实现“回源请求限流”:对同一个key的并发回源请求,用
INCR+EXPIRE组合计数,超阈值则返回缓存空值或降级响应 - 空值缓存本身要带短TTL(如60秒),避免永久拦截真实新增数据;且必须和主数据更新强同步,否则删了用户却还一直返回空
- 如果服务已用Spring Cache抽象,别只配
@Cacheable,得补上@CachePut和@CacheEvict的显式刷新逻辑,确保布隆过滤器、空值、锁状态三者一致
当击穿已发生,限流如何避免DB彻底瘫痪
这是最现实的兜底场景:缓存失效+锁失效+多个实例同时回源,DB已开始喘不过气。此时网关限流的作用,是给DB争取“喘息窗口”,而非根治问题。
关键动作:
- 立即在网关层对对应API路径启用**紧急熔断+降级限流**,比如把
/api/v1/product/{id}的QPS从5000压到200,返回预置JSON或HTTP 429,而不是让请求继续排队等DB超时 - 限流键要带业务上下文,例如用
rate_limit:product_hitbreak:${ip}而非简单rate_limit:product,防止某IP恶意刷导致全局受限 - 配合Redis的
PTTL检查缓存剩余时间,若发现大量key TTL - 严禁在网关用Lua脚本做复杂判断(如解析URL参数提取product id再限流),性能损耗大且难以维护;应由下游服务上报击穿指标,网关只执行简单指令
真正难的不是写几行 INCR 或配个 redis-rate-limiter,而是让所有微服务对“同一个key的缓存生命周期、锁机制、空值策略、布隆过滤器更新时机”达成一致——契约比代码更重,漏掉任意一环,限流就只是纸面安慰。

















