搜索缓存治理Redis缓存一致性治理与故障处理 - 第1节
1.1 什么是缓存
缓存(Cache)是计算机系统中用于存储临时数据副本的高速存储层。当系统请求数据时,如果缓存中存在该数据,则直接返回缓存结果,从而避免每次都从原始数据源(如数据库、磁盘或远程服务)重新获取。
在搜索场景中,缓存通常位于应用层与数据库之间,用于存储热点搜索词、搜索结果列表、用户会话等高频访问数据。
核心思想: 用空间换时间 —— 通过额外的存储空间,换取数据访问速度的数量级提升。
缓存的工作模型
下图展示了缓存介入后的标准数据读取流程:
1.2 缓存的作用
缓存并非银弹,但在正确场景下能带来显著的性能收益。下表总结了缓存的核心作用及其在搜索系统中的典型体现:
| 作用维度 | 具体收益 | 搜索场景示例 |
|---|---|---|
| 降低延迟 | 内存读取 vs 磁盘读取:毫秒级 vs 十毫秒级 | 热门搜索词结果直接从 Redis 返回,响应时间 < 5ms |
| 减轻数据库压力 | 缓存命中率 90%+ 时,数据库 QPS 降低 10 倍以上 | 搜索建议、联想词缓存,避免频繁查询 MySQL |
| 提高系统吞吐量 | 单机 Redis 可支撑 10 万+ QPS,远超数据库 | 秒杀场景下的搜索结果缓存,扛住瞬时流量洪峰 |
| 平滑突发流量 | 缓存作为缓冲区,吸收峰值请求 | 突发热点事件导致搜索量暴增,缓存保护后端 |
实践建议: 缓存命中率是衡量缓存效果的核心指标。一般建议搜索场景的缓存命中率维持在 85% 以上,低于该阈值需要检查缓存策略或容量。
1.3 缓存穿透
定义: 查询一个根本不存在的数据。由于缓存中不存在该数据,每次请求都会穿透缓存直达数据库,导致数据库压力剧增,甚至被打垮。
产生原因
- 恶意攻击:攻击者构造大量不存在的 Key 发起请求。
- 业务漏洞:查询条件错误,导致 Key 在数据库中也不存在。
- 缓存与数据库数据不一致:数据已被删除,但缓存未及时清理。
解决方案对比
| 方案 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 缓存空对象 | 查询不存在的数据时,在缓存中写入一个空值(如 null),并设置较短的 TTL | 实现简单,通用性强 | 占用缓存空间;空值 TTL 内数据真实写入后仍返回空 |
| 布隆过滤器 | 在缓存前加一层布隆过滤器,判断 Key 是否存在 | 空间效率高,不存在误判为存在 | 存在误判率;不支持删除操作;实现复杂度较高 |
| 参数校验 | 在应用层对请求参数进行合法性校验,拦截明显无效的查询 | 零成本,从源头拦截 | 只能拦截格式错误,无法拦截合法但不存在的数据 |
注意: 缓存空对象时,TTL 不宜过长(建议 30-60 秒),否则可能导致数据长期不一致。布隆过滤器适合 Key 集合相对固定的场景,如用户 ID 范围已知。
1.4 缓存击穿
定义: 一个热点 Key 在缓存失效的瞬间,大量并发请求同时涌入,全部穿透到数据库,导致数据库压力瞬间飙升。
与缓存穿透的区别:缓存击穿针对的是存在但失效的热点数据,而缓存穿透针对的是根本不存在的数据。
典型场景
- 热门商品详情页缓存过期,大量用户同时访问。
- 热搜词缓存 TTL 到期,搜索流量集中涌入。
- 首页推荐列表缓存失效,所有用户请求同时回源。
解决方案
| 方案 | 实现方式 | 适用场景 |
|---|---|---|
| 互斥锁 (Mutex) | 缓存失效后,第一个请求获取锁并回源数据库,其他请求等待或重试 | 并发量中等,对一致性要求高 |
| 逻辑过期 | 缓存中存储逻辑过期时间,后台异步线程负责刷新,不真正删除缓存 | 允许短暂不一致,追求高可用 |
| 永不过期 + 定时刷新 | 热点 Key 不设置 TTL,由后台任务定期更新 | 数据更新频率可控,如配置类数据 |
推荐组合: 互斥锁 + 逻辑过期。互斥锁保证一致性,逻辑过期保证缓存不被打穿,两者结合能应对绝大多数击穿场景。
1.5 缓存雪崩
定义: 大量缓存 Key 在同一时间集中失效,或者缓存节点整体宕机,导致所有请求直接打到数据库,引发数据库崩溃甚至整个系统不可用。
缓存雪崩是三种异常中破坏力最大的,因为它涉及的是大规模的缓存失效,而非单个 Key。
常见诱因
- 大量 Key 设置了相同的 TTL(如统一设置为 1 小时),到期时同时失效。
- Redis 实例宕机或网络分区,导致整个缓存层不可用。
- 缓存集群扩容/缩容时,大量 Key 被重新分布,导致缓存 Miss 率骤升。
防御策略
| 策略 | 具体做法 | 效果 |
|---|---|---|
| TTL 随机化 | 在基础 TTL 上增加随机偏移量(如 ±20%) | 避免大量 Key 同时过期 |
| 多级缓存 | 本地缓存(如 Caffeine)+ 分布式缓存(Redis) | Redis 宕机时本地缓存仍可提供服务 |
| 缓存预热 | 系统启动或大促前,提前将热点数据加载到缓存 | 避免冷启动时的雪崩效应 |
| 限流降级 | 对回源数据库的请求进行限流,超出阈值直接返回默认值或错误 | 保护数据库不被击垮 |
| Redis 高可用 | 主从 + 哨兵 / Redis Cluster | 单点故障时自动切换,减少缓存层不可用时间 |
1.6 三种异常对比总结
为便于记忆和面试准备,下表将三种缓存异常的核心差异进行横向对比:
| 异常类型 | 问题本质 | 影响范围 | 核心解决思路 |
|---|---|---|---|
| 缓存穿透 | 查询不存在的数据 | 单个 Key 或少量 Key | 缓存空对象 / 布隆过滤器 |
| 缓存击穿 | 热点 Key 失效瞬间并发回源 | 单个热点 Key | 互斥锁 / 逻辑过期 |
| 缓存雪崩 | 大量 Key 同时失效或缓存层宕机 | 全局 / 大规模 | TTL 随机化 / 多级缓存 / 高可用 |
面试高频题: “请分别解释缓存穿透、击穿、雪崩的区别,并给出至少两种解决方案。” 掌握本章内容即可从容应答。