服务器启动缓存预热技术

缓存预热(Cache Warming),本质上是:

在流量真正到达之前,把未来会被访问的数据提前放进缓存,从而避免冷启动时大量请求直接打到数据库或下游服务。


1.为什么需要缓存预热

1
2
3
4
5
6
7
8
9
10
11
12
用户请求

Cache
├── HIT → 直接返回

└── MISS

DB / API

写入 Cache

返回

缓存失效:

  • 服务重启
  • Redis 故障恢复
  • 集群扩容
  • 缓存全部过期
  • 发布新版本
  • 大促开始

那么瞬间会出现大量:

1
2
3
4
5
6
7
8
9
10
11
12
13
Cache MISS

大量请求同时查询DB

DB连接池耗尽

DB响应变慢

请求超时

重试

流量进一步放大

典型的 缓存击穿/冷启动雪崩

预热的目的:

1
2
3
4
5
请求来了 → 才加载

变成:

请求来之前 → 已经加载

2.缓存预热的几种方式

2.1启动时预热

服务启动后主动加载热点数据。

1
2
3
4
5
6
7
8
9
Application Start

读取热点Key列表

DB/ MQ/ 文件

写入Redis

Ready

适合:

  • 配置
  • 字典
  • 商品分类
  • 权限
  • 热门商品
  • 基础数据

元数据预热


2.2定时预热

按照固定周期更新热点数据:

1
2
3
4
5
6
7
   Scheduler

获取 Top N热点

查询数据

更新Cache

热点变化以后,你可能要等到下一次周期才能发现。因此通常会进一步演进成事件驱动


2.3事件驱动预热

这是比较成熟的方式如商品库存、价格、内容发生变化:

1
2
3
4
5
6
7
8
9
DB

CDC / Binlog

Kafka

Cache Consumer

Redis

或者:

1
2
3
4
5
6
7
8
9
商品更新

发布 ProductUpdated Event

消费者收到事件

查询最新商品

更新 Cache

这样缓存不是:

1
2
3
4
定期刷新

而是:
数据变化 → 缓存同步

典型场景:

  • 商品
  • 用户
  • 配置
  • 订单状态
  • 库存
  • 内容
  • 权限

2.4基于热点预测的预热

真正有价值的缓存预热,不是:

“把所有数据都放进去。”

而是:

只预热未来最可能访问的数据。

3. Redis预热时最容易犯的错误

3.1一次性全部加载

例如:

1
2
3
4
5
1000 万条数据

一次性查询

一次性写 Redis

结果可能是:

1
2
3
4
DB 内存压力
Redis 网络压力
应用 JVM OOM
Redis CPU 飙升

正确方式:

1
2
3
4
5
6
7
分页

Batch

限速

异步

控制预热速率。


3.2所有实例一起预热

例如 Kubernetes:

1
Pod × 100

每个 Pod 启动:

1
load 100 万数据

实际上:

1
100 × 100万

请求全部打向 DB应该把预热从:

1
2
3
4
5
6
7
Application

剥离成:
Warm-up Worker

或者使用:
Leader Election

只让一个节点负责。


4. 预热/缓存击穿要结合起来

即使做了预热,也无法保证 100% 命中。因此必须设计:

4.1Cache Miss防护

1
2
3
4
5
6
7
8
9
10
11
12
13
Request

Redis

MISS

Distributed Lock

只有一个线程查询DB

写Redis

其他线程读取结果

即:

1
2
3
           ┌→ DB → Redis
MISS → Lock┤
└→ Wait → Redis

这就是:
Single Flight / Mutex / Distributed Lock


4.2预热 + TTL 是一个关键矛盾

通常为了避免可能出现大量 Key 同时过期。因此通常加入随机TTL

随机 TTL

1
TTL = 30min + random(0~10min)

5. 生产级架构

1
2
3
4
5
6
7
8
9
10
11
12
13
   ┌──────────────┐
│ 用户请求流量 │
└──────┬───────┘

Cache
↙ ↘
HIT MISS
↓ ↓
Return SingleFlight

DB

Cache

需关注的指标

指标 意义
Cache Hit Rate 缓存命中率
Warm-up Hit Rate 预热数据实际命中率
Cache Miss QPS 未命中压力
DB QPS 缓存对DB的保护效果
Warm-up Duration 预热耗时
Warm-up Failure Rate 预热失败率
Redis CPU Redis 压力
Redis Memory 内存占用
Hot Key Count 热点 Key 数
Eviction Rate 淘汰速度
Stale Read Rate 过期/旧数据读取情况

其中一个非常重要的指标是:

预热命中贡献率

因为:预热了 100 万个 Key并不意味着预热有效。如果真正访问的只有:1000 个那就是资源浪费。


从本质上理解

缓存预热可以抽象成一个资源配置问题

1
2
3
4
5
6
7
有限 Cache 容量

有限预热成本

预测未来访问概率

选择最值得缓存的数据

所以真正的目标不是:让缓存尽可能满。 而是:让有限的缓存空间覆盖尽可能多的未来请求。