Skip to content

缓存架构

缓存是存储数据子集的高速存储层,访问速度比主存储快。缓存是提升系统性能、降低数据库负载、提高响应速度的有效手段。

缓存原理

局部性原理

局部性原理是缓存的理论基础。时间局部性:最近访问的数据很可能再次被访问。空间局部性:最近访问数据附近的数据很可能被访问。

缓存的本质是用空间换时间,通过存储热点数据,减少访问慢速存储(数据库、磁盘)的次数。

缓存命中率

缓存命中率 = 缓存命中次数 / 总访问次数。命中率越高,缓存效果越好。缓存命中率取决于:数据分布(是否集中热点)、缓存容量(能否存储热点)、淘汰策略(是否保留热点)、预取策略(是否提前加载)。

缓存模式

Cache-Aside(旁路缓存)

Cache-Aside 是最常用的缓存模式。读:先读缓存,缓存未命中则读数据库,然后写入缓存。写:先更新数据库,然后删除缓存(或更新缓存)。

Cache-Aside 的问题:缓存未命中时有缓存击穿风险(大量请求同时访问不存在的 key)。解决方案:布隆过滤器(快速判断 key 是否存在)、缓存空值(防止重复查询数据库)。

Read-Through(读穿透)

Read-Through 是缓存层负责从数据库加载数据。读:先读缓存,缓存未命中则缓存层读数据库并写入缓存。应用只与缓存交互,不直接访问数据库。

Read-Through 的好处:简化应用逻辑,缓存层统一管理数据加载。Read-Through 的代价:缓存层需要实现数据库访问逻辑。

Write-Through(写穿透)

Write-Through 是写数据时同时更新缓存和数据库。写:先更新数据库,然后更新缓存。缓存和数据库保持一致。

Write-Through 的好处:数据一致性强,缓存始终是最新的。Write-Through 的代价:写操作延迟高(需要同时更新缓存和数据库)。

Write-Behind(异步写)

Write-Behind 是写数据时只更新缓存,异步批量更新数据库。写:更新缓存,缓存层异步批量更新数据库。

Write-Behind 的好处:写操作延迟低,缓存层可以合并写操作。Write-Behind 的代价:数据可能丢失(缓存层崩溃时)、一致性弱(缓存和数据库可能不一致)。

缓存淘汰策略

LRU(Least Recently Used)

LRU 淘汰最近最少使用的数据。LRU 的实现:哈希表 + 双向链表。哈希表提供 O(1) 查找,双向链表记录访问顺序。

LRU 的问题:实现复杂(需要维护双向链表)、内存占用大(每个缓存项需要前驱和后继指针)。LRU 的改进:LRU-K(考虑最近 K 次访问)、Two Queues(二级 LRU)。

LFU(Least Frequently Used)

LFU 淘汰访问频率最低的数据。LFU 的实现:哈希表 + 优先队列(最小堆)。优先队列按访问频率排序,淘汰频率最低的数据。

LFU 的问题:新数据可能被淘汰(访问频率低但可能是热点)、实现复杂(需要维护优先队列)。LFU 的改进:LFU with Dynamic Aging(考虑时间因素,降低旧数据的频率)。

FIFO(First In First Out)

FIFO 淘汰最先加入的数据。FIFO 的实现:队列。FIFO 的问题:可能淘汰热点数据(热点数据是最先加入的)、不考虑访问频率。

Random(随机淘汰)

Random 随机淘汰数据。Random 的好处:实现简单、无额外开销。Random 的代价:可能淘汰热点数据、缓存命中率低。

缓存问题

缓存穿透

缓存穿透是查询不存在的数据,缓存和数据库都没有,导致每次请求都穿透到数据库。解决方案:布隆过滤器(快速判断 key 是否不存在)、缓存空值(缓存不存在的 key)、限流(防止恶意攻击)。

缓存击穿

缓存击穿是热点 key 过期,大量请求同时查询该 key,导致数据库压力突增。解决方案:加锁(只允许一个请求查询数据库)、热点 key 不过期(延长过期时间)、互斥锁(分布式锁)。

缓存雪崩

缓存雪崩是大量 key 同时过期,导致大量请求穿透到数据库。解决方案:过期时间加随机值(避免同时过期)、多级缓存(本地缓存 + 分布式缓存)、缓存高可用(集群部署)。

缓存一致性

一致性要求

强一致性:缓存和数据库的数据始终一致。最终一致性:缓存和数据库的数据最终一致,允许短暂不一致。弱一致性:不保证数据一致。

一致性方案

更新数据库后更新缓存:可能不一致(更新缓存失败)、延迟高(需要等待缓存更新)。更新数据库后删除缓存:可能不一致(删除缓存前有读请求)、延迟低。

延迟双删:先删除缓存,更新数据库,延迟后再删除缓存。延迟双删可以减少不一致窗口期。

监听 Binlog:通过监听数据库的 Binlog,异步更新缓存。监听 Binlog 可以保证最终一致性,但实现复杂(需要 Canal、Debezium 等工具)。

缓存类型

本地缓存

本地缓存是应用进程内的缓存,如 Guava、Caffeine、Ehcache。本地缓存的优势:速度快(无网络开销)、简单(无需额外部署)。本地缓存的问题:容量有限(受限于进程内存)、多实例不一致(每个实例的缓存独立)。

分布式缓存

分布式缓存是独立的缓存服务,如 Redis、Memcached。分布式缓存的优势:容量大(可扩展)、多实例共享(所有实例访问同一缓存)。分布式缓存的问题:网络开销、序列化开销、单点故障(需要集群)。

多级缓存

多级缓存是本地缓存 + 分布式缓存的组合。读:先读本地缓存,未命中则读分布式缓存,再未命中则读数据库。写:更新数据库,删除分布式缓存,删除本地缓存。

多级缓存的好处:减少网络开销(本地缓存命中率高)、降低分布式缓存压力。多级缓存的问题:一致性复杂(多级缓存同步)、本地缓存占用内存。

缓存应用

页面缓存

缓存渲染后的 HTML 页面,减少数据库查询和页面渲染。适用场景:静态页面、访问量大的首页、新闻列表。

对象缓存

缓存查询结果(如用户信息、商品信息),减少数据库查询。适用场景:热点数据、读多写少的数据。

查询缓存

缓存数据库查询结果(如 SELECT 结果),减少数据库查询。适用场景:复杂查询、频繁查询。

缓存是提升系统性能的有效手段,但也会引入一致性问题。理解缓存的模式、淘汰策略、一致性问题,有助于设计合适的缓存架构。