缓存

146 阅读4分钟

思维导图

缓存.png

缓存技术作为现代高并发系统的核心组件,其设计模式直接影响系统的性能和一致性。本文将从缓存的分层架构出发,深入剖析三种主流缓存模式的设计原理、适用场景及潜在问题,帮助开发者构建更可靠的缓存体系。


一、缓存体系分层架构

  1. 接入层
    负责接收用户请求,处理业务逻辑,是系统与用户交互的第一道防线。在旁路缓存模式下,接入层承担缓存策略的决策权。
  2. 缓存层
    由Redis、Memcached等高速存储介质构成,提供快速数据访问能力。其核心价值在于降低数据库负载,提升系统吞吐量。
  3. 存储层
    以MySQL、MongoDB等持久化数据库为基础,保障数据最终一致性,是系统数据的唯一可信来源。

二、主流缓存模式解析

1. 旁路缓存模式(Cache-Aside)

核心思想:缓存作为数据库的辅助层,由接入层主动控制缓存策略。

读流程

当用户程序获取某个数据的时候,接入层首先去缓存层进行查询,如果命中,则直接返回,如果没有命中,接入层就去存储层进行查询,然后写入一份数据到缓存,并返回用户请求数据

def read_data(key):
    data = cache.get(key)
    if data is None:
        data = db.query(key)  # 存储层查询
        cache.set(key, data)  # 回填缓存
    return data

当用户程序写入某个数据的时候,先写入存储层,存储层写入完成后,删除掉缓存模块中缓存条目

写流程
def write_data(key, value):
    db.update(key, value)  # 优先写入存储层
    cache.delete(key)       # 失效旧缓存
关键设计原则
  • 删除而非更新:避免并发写覆盖问题(如线程A覆盖线程B的更新结果)。
  • 先写库再删缓存:防止中间状态被读请求捕获(如删除缓存后写库失败)。
  • 延迟双删策略:应对极端时序问题(写后延迟二次删除缓存)。
典型问题与应对
问题类型场景示例解决方案
缓存击穿热点Key失效后高并发查询互斥锁、熔断降级
主从延迟读从库导致缓存旧数据强制主库读、延迟缓存回填
冷启动问题新系统无缓存导致穿透预热加载、布隆过滤器

适用场景:读多写少型业务(如新闻详情页、商品信息展示)。


2. 读写穿透模式(Read/Write-Through)

核心思想:缓存层作为数据访问的统一入口,接管缓存策略的复杂性。

架构对比
旁路缓存:
用户请求 → 接入层 → 缓存层 → 存储层

读写穿透:
用户请求 → 缓存层 → 存储层
写流程原子性保障
def write_through(key):
    lock = redisson.getLock(key)
    lock.lock()
    cache.update(key, value) // 更新缓存
    db.update(key, value)  // 同步写库
    lock.unlock()
优势与挑战
  • 优点:彻底解决冷启动问题,降低接入层复杂度。
  • 缺点:写操作需同步更新缓存和数据库,可能引发资源竞争。

适用场景:写后立即高频读的业务(如秒杀库存更新)。


3. 异步回写模式(Write-Behind)

设计理念:以缓存层为唯一入口,异步批量持久化数据。

数据流示意图
用户请求 → 缓存层
                ├─ 读请求:直接响应
                └─ 写请求:缓存后异步批量刷盘
持久化保障方案
  • SSD+机械硬盘分层存储
    使用NVMe SSD作为一级缓存介质,结合机械硬盘实现低成本持久化。
  • WAL日志(Write-Ahead Logging)
    即使宕机,也能通过日志恢复未刷盘数据。

典型应用:Linux内核PageCache机制、消息队列的磁盘持久化。


三、模式对比与选型建议

维度旁路缓存读写穿透异步回写
一致性最终一致强一致最终一致
复杂度接入层逻辑复杂缓存层逻辑复杂架构复杂
吞吐量中等中等极高
数据安全依赖数据库持久化同步持久化需额外保护机制
适用场景读多写少写后立即读超高并发写入

选型策略

  1. 优先旁路缓存:适用于大多数Web场景,技术生态成熟。
  2. 慎用异步回写:仅在可接受数据丢失时使用(如实时日志采集)。
  3. 读写穿透的折中:适合需要强一致性的金融交易类系统。