2. 缓存基础:缓存的定义、缓存命中率、缓存穿透、缓存雪崩、缓存击穿
在构建高性能 API 网关时,缓存是降低后端数据库负载、缩短响应延迟的核心手段。然而,缓存并非银弹——错误的使用方式会导致系统雪崩或数据不一致。本节从缓存的基本定义出发,逐步剖析命中率、穿透、雪崩、击穿四大关键概念,为后续的网关缓存与 DB 一致性校验实践奠定理论基础。
2.1 缓存的定义与工作原理
缓存(Cache)是一种将数据临时存储在高速存储介质(如内存)中的技术,目的是加速后续相同数据的访问。在 API 网关场景中,缓存通常位于客户端与后端服务之间,用于存储频繁查询的响应结果。
核心公式: 缓存加速比 = 原始访问延迟 / 缓存访问延迟。理想情况下,缓存访问延迟应比 DB 访问低 1~3 个数量级。
缓存系统的基本工作流程包含三个步骤:
- 查询缓存: 请求到达时,网关首先检查缓存中是否存在目标键(Key)。
- 缓存命中: 若存在,直接返回缓存值,跳过后端 DB。
- 缓存未命中: 若不存在,回源到 DB 查询,将结果写入缓存后再返回。
2.2 缓存命中率
缓存命中率(Cache Hit Ratio)是衡量缓存效率的核心指标,定义为缓存命中的请求数占总请求数的百分比。
| 指标 | 公式 | 理想范围 | 说明 |
|---|---|---|---|
| 命中率 | 命中次数 / (命中次数 + 未命中次数) × 100% | ≥ 90% | 命中率越高,DB 压力越小 |
| 未命中率 | 1 - 命中率 | ≤ 10% | 未命中率过高需排查缓存策略 |
| 字节命中率 | 缓存提供的数据量 / 总请求数据量 | ≥ 80% | 适用于大对象缓存场景 |
实践建议: 在 API 网关中,应针对每个路由(Route)分别统计命中率。若某路由命中率持续低于 70%,应考虑调整 TTL、预热策略或检查 Key 设计是否合理。
2.3 缓存穿透
缓存穿透 指请求查询一个缓存和数据库中都不存在的数据。由于缓存未命中,每次请求都会穿透到 DB,导致 DB 承受大量无效查询,严重时可能拖垮数据库。
典型场景:恶意攻击者频繁请求不存在的用户 ID(如负数 ID 或随机 UUID)。
解决方案对比
| 方案 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 缓存空对象 | 将 null 或特殊标记写入缓存,设置短 TTL(如 30s) | 实现简单,通用性强 | 占用缓存空间,短时间大量空 Key 仍可能冲击 DB |
| 布隆过滤器 | 在网关层维护一个位图结构,快速判断 Key 是否存在 | 空间效率极高,不存在误判为存在 | 存在误判为不存在(假阳性),需定期重建 |
| 参数校验 + 限流 | 在网关层拦截非法参数,对异常请求直接拒绝 | 从源头阻断无效请求 | 无法防御合法参数但数据不存在的情况 |
2.4 缓存雪崩
缓存雪崩 指大量缓存 Key 在同一时间过期失效,或缓存节点宕机,导致所有请求瞬间涌入 DB,造成数据库压力激增甚至崩溃。
雪崩与穿透的区别:穿透针对不存在的数据,雪崩针对存在但已过期的数据。
预防策略
- 均匀过期: 在基础 TTL 上增加随机偏移量(如 ±10%),避免大量 Key 同时过期。
- 多级缓存: 本地缓存(如 Caffeine)+ 分布式缓存(如 Redis)分层部署,本地缓存失效后仍可命中 Redis。
- 缓存预热: 系统启动或大促前,提前将热点数据加载到缓存中。
- 限流降级: 网关层配置熔断和限流,当 DB 负载超过阈值时直接返回降级响应。
注意: 缓存雪崩的恢复比穿透更困难,因为雪崩时 DB 可能已经处于过载状态,需要配合熔断和渐进式恢复策略。
2.5 缓存击穿
缓存击穿 指一个热点 Key 在缓存过期的瞬间,大量并发请求同时访问该 Key,导致所有请求都穿透到 DB。击穿是雪崩的一种特例——雪崩是大量 Key 同时失效,击穿是单个热点 Key 失效。
解决方案对比
| 方案 | 原理 | 适用场景 | 注意事项 |
|---|---|---|---|
| 互斥锁(Mutex) | 第一个请求获取锁并回源 DB,其他请求等待或快速失败 | 并发量极高,数据一致性要求严格 | 需防止死锁,锁超时时间应合理设置 |
| 逻辑过期 | 缓存永不过期,但数据内嵌逻辑过期时间,异步线程更新 | 允许短暂数据不一致 | 需额外维护异步更新线程池 |
| 二级缓存 | 热点 Key 在本地缓存和 Redis 中各存一份,本地缓存 TTL 更短 | 读多写少,对一致性要求不高 | 本地缓存占用 JVM 内存 |
2.6 三种异常对比总结
| 维度 | 缓存穿透 | 缓存雪崩 | 缓存击穿 |
|---|---|---|---|
| 根本原因 | 查询不存在的数据 | 大量 Key 同时过期 / 节点宕机 | 热点 Key 过期 + 高并发 |
| 影响范围 | 单个 Key 或少量 Key | 全局或大面积 | 单个热点 Key |
| DB 压力特征 | 持续低效查询 | 瞬时洪峰 | 瞬时高并发穿透 |
| 首选方案 | 布隆过滤器 | 均匀过期 + 多级缓存 | 互斥锁 |
| 网关层干预 | 参数校验 + 限流 | 限流 + 熔断降级 | 分布式锁 + 本地缓存 |
网关实践要点: 在 OpenAPI 网关中,建议对每个路由配置独立的缓存策略。对于高频查询接口(如用户信息、商品详情),优先使用“缓存空对象 + 布隆过滤器”组合防御穿透;对于大促场景,提前执行缓存预热并启用二级缓存,防止雪崩和击穿。