服务器启动缓存预热技术
缓存预热(Cache Warming),本质上是:
在流量真正到达之前,把未来会被访问的数据提前放进缓存,从而避免冷启动时大量请求直接打到数据库或下游服务。
1.为什么需要缓存预热
1 | 用户请求 |
缓存失效:
- 服务重启
- Redis 故障恢复
- 集群扩容
- 缓存全部过期
- 发布新版本
- 大促开始
那么瞬间会出现大量:
1 | Cache MISS |
典型的 缓存击穿/冷启动雪崩。
预热的目的:
1 | 请求来了 → 才加载 |
2.缓存预热的几种方式
2.1启动时预热
服务启动后主动加载热点数据。
1 | Application Start |
适合:
- 配置
- 字典
- 商品分类
- 权限
- 热门商品
- 基础数据
元数据预热
2.2定时预热
按照固定周期更新热点数据:
1 | Scheduler |
热点变化以后,你可能要等到下一次周期才能发现。因此通常会进一步演进成事件驱动。
2.3事件驱动预热
这是比较成熟的方式如商品库存、价格、内容发生变化:
1 | DB |
或者:
1 | 商品更新 |
这样缓存不是:
1 | 定期刷新 |
典型场景:
- 商品
- 用户
- 配置
- 订单状态
- 库存
- 内容
- 权限
2.4基于热点预测的预热
真正有价值的缓存预热,不是:
“把所有数据都放进去。”
而是:
只预热未来最可能访问的数据。
3. Redis预热时最容易犯的错误
3.1一次性全部加载
例如:
1 | 1000 万条数据 |
结果可能是:
1 | DB 内存压力 |
正确方式:
1 | 分页 |
控制预热速率。
3.2所有实例一起预热
例如 Kubernetes:
1 | Pod × 100 |
每个 Pod 启动:
1 | load 100 万数据 |
实际上:
1 | 100 × 100万 |
请求全部打向 DB应该把预热从:
1 | Application |
只让一个节点负责。
4. 预热/缓存击穿要结合起来
即使做了预热,也无法保证 100% 命中。因此必须设计:
4.1Cache Miss防护
1 | Request |
即:
1 | ┌→ DB → Redis |
这就是:
Single Flight / Mutex / Distributed Lock
4.2预热 + TTL 是一个关键矛盾
通常为了避免可能出现大量 Key 同时过期。因此通常加入随机TTL
随机 TTL
1 | TTL = 30min + random(0~10min) |
5. 生产级架构
1 | ┌──────────────┐ |
需关注的指标
| 指标 | 意义 |
|---|---|
| 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 | 有限 Cache 容量 |
所以真正的目标不是:让缓存尽可能满。 而是:让有限的缓存空间覆盖尽可能多的未来请求。