2. 缓存基础回顾:缓存的定义与作用、常见缓存模式、缓存穿透/击穿/雪崩概念

2.1 缓存的定义与作用

缓存(Cache) 是一种将数据存储在临时存储层中的技术,其核心目标是 加速数据访问 并 降低后端系统的负载。在分布式系统与 Kubernetes 部署中,缓存通常位于应用与持久化存储(如数据库、磁盘)之间,利用内存的高速读写特性来减少 I/O 延迟。

缓存的核心作用:
  • 降低延迟: 内存访问延迟通常在微秒级,而磁盘或网络数据库访问延迟在毫秒级,缓存可将响应时间降低 1~3 个数量级。
  • 提升吞吐量: 缓存层能承载更高的并发请求,避免后端数据库成为瓶颈。
  • 保护后端系统: 通过吸收突发流量,防止数据库因过载而崩溃。
  • 减少成本: 降低对高性能数据库实例的依赖,允许使用更经济的存储方案。
缓存在系统架构中的位置 缓存在系统架构中的位置 客户端 应用服务 缓存层 数据库 缓存的作用路径 ① 客户端请求 → 应用服务 → 查询缓存(命中则直接返回) ② 缓存未命中 → 查询数据库 → 回填缓存 → 返回结果

2.2 常见缓存模式

在分布式缓存治理中,应用与缓存之间的交互遵循几种经典模式。理解这些模式是设计缓存一致性策略的前提。

模式 读操作 写操作 一致性保证 适用场景
Cache-Aside 应用先读缓存,未命中则读 DB 并回填 应用先写 DB,再删除/更新缓存 最终一致性(需处理并发写) 通用场景,Kubernetes 中最常见
Read-Through 缓存层自动从 DB 加载(应用无感知) 应用直接写 DB 弱一致性(缓存可能滞后) 读密集、数据变化不频繁
Write-Through 同 Read-Through 应用写缓存,缓存同步写 DB 强一致性(写路径同步) 对一致性要求高的场景
Write-Behind 同 Read-Through 应用写缓存,缓存异步批量写 DB 最终一致性(有数据丢失风险) 写密集、可容忍短暂不一致

2.2.1 Cache-Aside(旁路缓存)

这是 Kubernetes 部署中最常用的模式。应用代码显式管理缓存与数据库的交互。读操作时,若缓存未命中,应用负责从数据库加载数据并回填缓存;写操作时,应用先更新数据库,再使缓存失效(删除或更新)。

最佳实践: 在 Cache-Aside 模式中,写操作推荐使用 删除缓存 而非更新缓存。删除操作更简单,且能避免并发写导致的脏数据问题。

2.2.2 Read-Through / Write-Through / Write-Behind

这三种模式将缓存与数据库的同步逻辑封装在缓存层内部,对应用透明。在 Kubernetes 环境中,通常由 Sidecar 代理或专门的缓存中间件(如 Redis Enterprise、Hazelcast)实现。

  • Read-Through: 缓存未命中时,缓存组件自动从数据库加载数据。适合读多写少的场景。
  • Write-Through: 每次写操作都同步写入缓存和数据库,保证强一致性,但写延迟较高。
  • Write-Behind: 写操作先写入缓存,然后异步批量写入数据库。能显著提升写吞吐量,但存在数据丢失风险(缓存宕机时)。
四种缓存模式对比 四种缓存模式对比 Cache-Aside 读: 应用→缓存→DB 写: 应用→DB→删缓存 一致性: 最终 控制权: 应用层 复杂度: 低 Read-Through 读: 缓存自动加载DB 写: 应用直接写DB 一致性: 弱 控制权: 缓存层 复杂度: 中 Write-Through 读: 缓存自动加载DB 写: 缓存同步写DB 一致性: 强 控制权: 缓存层 复杂度: 中 Write-Behind 读: 缓存自动加载DB 写: 缓存异步写DB 一致性: 最终 控制权: 缓存层 复杂度: 高 模式选择建议 • Cache-Aside:Kubernetes 微服务首选,灵活可控,适合大多数业务场景。 • Read-Through:适合读多写少、数据变化不频繁的配置类数据。 • Write-Through:适合需要强一致性的金融、交易类场景,但写延迟较高。 • Write-Behind:适合日志、监控等写密集型场景,需配合持久化机制防止数据丢失。

2.3 缓存穿透 / 击穿 / 雪崩

这三个概念是缓存治理中必须应对的经典故障场景,在 Kubernetes 集群中由于 Pod 动态扩缩容、网络抖动等因素,发生概率更高。

故障类型 现象 根本原因 典型后果
缓存穿透 请求直接打到数据库,缓存形同虚设 查询不存在的数据(缓存和数据库都没有) 数据库负载飙升,可能宕机
缓存击穿 热点 Key 过期瞬间,大量请求涌入数据库 单个热点 Key 在缓存中失效 数据库瞬间高负载,响应变慢
缓存雪崩 大量缓存同时失效,数据库被压垮 大量 Key 设置了相同的过期时间 数据库崩溃,系统不可用

2.3.1 缓存穿透

当请求查询一个既不在缓存中也不在数据库中的数据时,每次请求都会穿透缓存直达数据库。攻击者可以利用这一点构造大量不存在的 Key 进行恶意请求。

治理策略:
  • 缓存空值: 将查询结果为空的 Key 也缓存起来(设置较短的 TTL,如 30~60 秒)。
  • 布隆过滤器: 在缓存前加一层布隆过滤器,快速判断 Key 是否存在。
  • 参数校验: 在应用层对请求参数进行合法性校验,拦截明显无效的请求。

2.3.2 缓存击穿

某个热点 Key 在缓存中过期失效的瞬间,大量并发请求同时发现缓存未命中,全部涌向数据库。与穿透不同,击穿针对的是确实存在但缓存刚好失效的数据。

治理策略:
  • 互斥锁(Mutex): 只允许一个线程去数据库加载数据,其他线程等待或重试。
  • 逻辑过期: 缓存永不过期,但数据中携带逻辑过期时间,异步刷新。
  • 热点 Key 不过期: 对已知热点数据设置永不过期,由后台任务定期更新。

2.3.3 缓存雪崩

大量缓存 Key 在同一时间集中过期,导致数据库瞬间承受巨大压力。在 Kubernetes 中,如果多个 Pod 同时启动并初始化缓存,也可能触发雪崩效应。

治理策略:
  • 过期时间随机化: 在基础 TTL 上增加随机偏移量(如 ±10%~30%),避免集中过期。
  • 多级缓存: 本地缓存(如 Caffeine)+ 分布式缓存(如 Redis)组合,分散压力。
  • 限流降级: 在数据库访问层实施限流,保护后端系统。
  • 预热缓存: 在业务低峰期提前加载热点数据到缓存中。
缓存穿透/击穿/雪崩对比 缓存穿透 / 击穿 / 雪崩对比 缓存穿透 请求不存在的数据 缓存: 未命中 数据库: 也没有 后果: 每次请求都打DB 解决: 缓存空值/布隆过滤器 缓存击穿 热点Key过期瞬间 缓存: 刚好失效 数据库: 有数据 后果: 大量并发打DB 解决: 互斥锁/逻辑过期 缓存雪崩 大量Key同时过期 缓存: 批量失效 数据库: 有数据 后果: DB瞬间被压垮 解决: TTL随机化/多级缓存 Kubernetes 环境下的特殊风险 • Pod 重启/扩缩容时,本地缓存全部丢失,可能触发雪崩。 • 服务网格(Service Mesh)中的 Sidecar 可能放大穿透效应。 • 建议结合 Kubernetes HPA 设置缓存预热 Job,避免冷启动冲击。

2.4 本章小结