这是 Beta 探索课程,内容结构、实验步骤和示例可能会继续调整。
缓存策略
问题引入
上一节我给所有天气数据都设置了 1 小时的缓存时间。
上线运行一段时间后,我收到了用户的反馈:
用户 A:"为什么你们的数据总是比气象局慢?"
用户 B:"现在外面在下雨,你们 API 还显示晴天"
用户 C:"能不能实时更新天气数据?"我意识到:1 小时的缓存时间太长了。
但是,如果缩短缓存时间:
- 外部 API 调用量会增加
- 响应时间会变慢
如何平衡性能和数据新鲜度?这成了我接下来要解决的问题。
数据分析
我研究了不同天气数据的变化规律:
当前温度
变化频率:实时变化
变化幅度:每分钟变化 0-1 度
用户期望:尽可能实时天气状况
变化频率:几个小时变化一次
变化幅度:从晴天→阴天→雨天
用户期望:1 小时内更新即可城市信息
变化频率:几乎不变
变化幅度:城市名、经纬度不变
用户期望:永久缓存湿度数据
变化频率:几十分钟变化一次
变化幅度:变化 5-10%
用户期望:30 分钟内更新分析完后,我明白了:不同数据的变化频率不同,不能用一个缓存时间对付所有情况。
优化策略
根据不同数据的变化频率,我设计了不同的缓存策略:
策略 1:分层缓存
设计流程
策略 1:分层缓存
- 步骤 1:按命中、未命中和异常 key 处理读取与回源
- 步骤 2:按本节策略读取、写入缓存并处理过期或失效
- 步骤 3:校验身份、密钥或权限
关注点:命中率、回源压力、TTL 和异常 key 处理。
缓存时间设置
| 数据类型 | 缓存时间 | 理由 |
|---|---|---|
| 实时温度 | 5 分钟 | 温度变化较快,用户期望实时 |
| 天气状况 | 1 小时 | 天气状况变化较慢 |
| 湿度数据 | 30 分钟 | 湿度变化中等速度 |
| 城市信息 | 24 小时 | 城市信息几乎不变 |
| 完整数据 | 10 分钟 | 平衡性能和新鲜度 |
策略 2:主动更新
有些关键数据,我不能等缓存过期才更新。
定时更新任务
设计流程
定时更新任务
- 步骤 1:写入缓存值、空值标记或热点保护状态
- 步骤 2:按本节策略读取、写入缓存并处理过期或失效
- 步骤 3:识别请求 key、缓存命中状态和回源数据对象
- 步骤 4:根据命中率、数据新鲜度和回源压力调整策略
关注点:命中率、回源压力、TTL 和异常 key 处理。
优势:
- 用户访问时,缓存已经是新的
- 热门城市数据始终保持新鲜
劣势:
- 增加了外部 API 调用量
- 需要维护热门城市列表
这个方案让我想起了”预加载”的概念——在用户需要之前,先把数据准备好。
策略 3:用户触发更新
允许用户主动刷新数据:
设计流程
策略 3:用户触发更新
- 步骤 1:按命中、未命中和异常 key 处理读取与回源
- 步骤 2:按本节策略读取、写入缓存并处理过期或失效
- 步骤 3:校验身份、密钥或权限
关注点:命中率、回源压力、TTL 和异常 key 处理。
使用方式:
# 普通请求(使用缓存)
GET /api/weather?city=北京
# 强制刷新(跳过缓存)
GET /api/weather?city=北京&refresh=true这个方案把选择权交给了用户——对实时性要求高的场景,他们可以主动刷新。
最终方案
综合以上策略,我设计了这样的方案:
1. 分层缓存
- 根据数据变化频率设置不同的缓存时间
- 减少不必要的外部 API 调用
2. 定时更新
- 对热门城市(Top 10)每 10 分钟主动更新
- 保证高频访问城市的数据新鲜度
3. 用户可选
- 提供 refresh 参数,让用户可以选择强制刷新
- 满足对实时性要求高的场景
效果对比
优化前
| 指标 | 数值 |
|---|---|
| 平均响应时间 | 2000ms |
| 外部 API 调用量 | 10 万次/天 |
| 数据新鲜度 | 最多延迟 1 小时 |
优化后(简单缓存)
| 指标 | 数值 |
|---|---|
| 平均响应时间 | 35ms |
| 外部 API 调用量 | 5000 次/天 |
| 数据新鲜度 | 最多延迟 1 小时 |
优化后(分层缓存)
| 指标 | 数值 |
|---|---|
| 平均响应时间 | 40ms |
| 外部 API 调用量 | 8000 次/天 |
| 数据延迟: | |
| - 温度数据 | 最多 5 分钟 |
| - 天气状况 | 最多 1 小时 |
| - 热门城市 | 最多 10 分钟 |
权衡思考
分层缓存 vs 简单缓存:
| 维度 | 简单缓存 | 分层缓存 |
|---|---|---|
| 响应时间 | 35ms | 40ms |
| API 调用量 | 5000 次/天 | 8000 次/天 |
| 数据新鲜度 | 1 小时 | 5-60 分钟 |
| 维护复杂度 | 简单 | 中等 |
我的结论: 对于天气数据,用户对数据新鲜度的要求高于响应时间,分层缓存是更好的选择。
虽然维护复杂度增加了一些,但用户体验的提升是值得的。