高并发系统设计-缓存保护

一、概述

1.1 什么是缓存保护

缓存保护(Cache Protection)是指:

通过一系列缓存设计策略,避免缓存异常导致数据库被大量请求直接访问,从而保证系统稳定性。

典型架构:

                Client
             Gateway
            Application
         ┌─────────┴─────────┐
         │                   │
         ▼                   ▼
     Local Cache         Redis Cache
                     Cache Miss?
                            MySQL

1.2 为什么需要缓存保护

Redis 可以承受几十万甚至百万级 QPS,而 MySQL 通常只能支撑几千 QPS。

例如:

Redis

100000 QPS
MySQL

3000 QPS

如果 Redis 出现问题:

100000 请求
全部进入 MySQL
数据库连接耗尽
整个系统崩溃

缓存的首要目标是保护数据库,其次才是提升访问性能。

1.3 企业缓存架构

企业通常采用:

            Client
          Application
        Local Cache(Caffeine)
         Redis Cluster
            MySQL

同时配合:

  • Bloom Filter
  • 分布式锁
  • 逻辑过期
  • 多级缓存
  • 消息队列

共同组成完整的缓存保护体系。

1.4 缓存问题分类

  • 缓存穿透(Cache Penetration)
  • 缓存击穿(Cache Breakdown)
  • 缓存雪崩(Cache Avalanche)
  • 热点 Key(Hot Key)
  • 大 Key(Big Key)
  • 缓存一致性(Cache Consistency)

这些问题如果处理不当,都可能导致数据库在短时间内承受无法处理的流量。

二、缓存穿透

2.1 介绍

缓存穿透是指:

查询一个数据库和缓存中都不存在的数据,导致每次请求都会直接访问数据库。

攻击者可以利用这一点发起恶意请求,使数据库承受巨大压力。

2.2 原理

由于缓存中没有记录"不存在"这一事实,所以每次都会重复查询数据库。

2.3 解决方案

方案一:缓存空值(Null Cache)

数据库不存在:

key -> NUL LTTL = 60s

下次直接命中空值。

优点:

  • 简单
  • 成本低

缺点:

  • 占用少量缓存空间
  • 数据新增后需要及时失效

方案二:Bloom Filter(企业推荐)

所有合法 Key:

UserID->Bloom Filter->不存在->直接返回

根本不会访问 Redis 和 MySQL。

优点:

  • 内存占用极低
  • 非常适合海量数据

缺点:

  • 存在一定误判率(可能误判存在,但不会误判不存在)

方案三:接口参数校验

例如:

UserId < 0
直接返回

避免无效请求进入业务系统。

三、缓存击穿(Cache Breakdown)

3.1 介绍

缓存击穿是指:

某一个热点 Key 在失效瞬间,大量请求同时访问数据库。

问题核心:

热点数据 + 缓存失效

3.3 解决方案

方案一:分布式锁(企业最常用)

只有一个线程回源数据库:

Redis Miss
获取 Lock
成功
查询数据库
写 Redis
释放 Lock

其它线程等待或返回旧数据。

方案二:逻辑过期(推荐)

缓存不真正删除:

Redis
数据 + expire_time

读取:

未过期
直接返回

过期
后台异步刷新

用户始终可以获取数据。

方案三:热点数据永不过期

例如:

  • 系统配置
  • 地区信息
  • 字典数据

后台主动更新。

四、缓存雪崩(Cache Avalanche)

4.1 介绍

缓存雪崩是指:

大量缓存 Key 在同一时间失效,导致数据库压力骤增。

4.2 原理

Redis

100万个Key
同一时间过期
全部访问数据库

4.3 解决方案

方案一:随机过期时间(企业标准)

不要统一:3600

而是:3600~4200 秒

避免集中失效。

方案二:多级缓存

Local Cache
Redis
MySQL

降低数据库压力。

方案三:缓存预热

系统启动时:

提前加载热点数据。

五、热点 Key(Hot Key)

5.1 介绍

热点 Key 是指:

某一个缓存 Key 的访问量远高于其他 Key。

例如:

  • 首页推荐
  • 商品详情

5.2 原理

100万请求
同一个Key
Redis CPU飙高

5.3 解决方案

方案一、本地缓存

减少网络访问。

方案二、Redis Cluster

热点数据分散。

方案三、多副本缓存

例如

product:1001_1

product:1001_2

product:1001_3

随机读取。

六、大 Key(Big Key)

6.1 介绍

Big Key 是指:

单个 Key 存储的数据量过大。

例如:

一个 List,500万条数据

6.2 原理

读取:

GET
几十 MB
网络阻塞

删除:

DEL
Redis 卡顿

6.3 解决方案

方案一、数据拆分

例如:

user:1:page:1

user:1:page:2

方案二、使用 SCAN

避免:

KEYS *

异步删除:

UNLINK key

避免 Redis 主线程阻塞。

七、缓存一致性(Cache Consistency)

7.1 介绍

缓存一致性是指:

缓存中的数据与数据库中的数据保持一致。

7.2 原理

问题通常发生在:

更新数据库
缓存未更新

或:

更新缓存
数据库更新失败

7.3 解决方案

方案一、延迟双删

流程:

删除缓存
更新数据库
延迟删除缓存

方案二、Cache Aside(推荐)

读:

Redis
MySQL
Redis

写:

MySQL
删除 Redis

这是目前企业最广泛采用的缓存模式。

方案三、MQ 异步更新

更新数据库
发送 MQ
更新缓存

适用于高并发场景。

八、最佳实践

建议组合使用:

             Client
             Gateway
         Local Cache
        Redis Cluster
      ┌─────────┴─────────┐
      │                   │
Bloom Filter         Mutex Lock
      │                   │
      └─────────┬─────────┘
              MySQL
           MQ 更新缓存

推荐策略:

  • 缓存穿透 → Bloom Filter + 空值缓存
  • 缓存击穿 → 分布式锁 + 逻辑过期
  • 缓存雪崩 → 随机 TTL + 缓存预热 + 多级缓存
  • 热点 Key → 本地缓存 + 多副本 + Redis Cluster
  • 大 Key → 数据拆分 + SCAN + UNLINK
  • 缓存一致性 → Cache Aside + 延迟双删 + MQ