缓存不是"加个Redis就行"
我第一次用Redis的想法很简单:把热门数据往Redis一塞,搞定。
结果用了三个月,Redis内存占用飙到3G,缓存命中率只有34%。花了两天排查,发现大部分缓存都是该缓存的没缓存,不该缓存的全缓存了。
我踩过的三个缓存坑
坑1:缓存了不该缓存的数据
- 用户个人信息(每个用户不一样,缓存命中率极低)
- 实时库存数据(缓存的库存和实际对不上,用户下单了发现没货)
坑2:没缓存该缓存的数据
- 首页推荐(每秒钟几十次查询,每次都查数据库)
- 分类列表(一天才变一次的配置,不缓存等于白给数据库压力)
坑3:缓存过期策略混乱
之前:所有缓存统一 1 小时过期
结果:首页缓存的过期了,需要重新查库,瞬间 QPS 暴涨
菜单配置的缓存明明没变化,也跟着过期重载
正确的缓存分层策略
L1: 浏览器缓存(不变的数据)
- 静态资源(CSS/JS/图片)
- 设置 1 年过期 + hash 版本号
L2: CDN 缓存(公开数据)
- 首页、分类页
- 设置 5 分钟过期
L3: Redis 缓存(热数据)
- 用户 Session:30 分钟
- 搜索结果:5 分钟
- 配置数据:24 小时(有变更时主动失效)
- 热点文章:1 小时
L4: 数据库(冷数据)
- 历史订单、归档数据
- 不缓存,按需查询
缓存更新的最佳实践
// Cache-Aside 模式
async function getRestaurant(id: string) {
const cached = await redis.get(`restaurant:${id}`)
if (cached) return JSON.parse(cached)
const data = await db.query('SELECT * FROM restaurants WHERE id = $1', [id])
if (data) {
await redis.set(`restaurant:${id}`, JSON.stringify(data), 'EX', 3600)
}
return data
}
async function updateRestaurant(id: string, data: any) {
await db.query('UPDATE restaurants SET ... WHERE id = $1', [id])
await redis.del(`restaurant:${id}`) // 删除缓存,下次查询自动重建
}
关键:更新时删除缓存,查询时重建缓存。不要更新缓存——删除比更新简单得多,而且避免了并发更新的数据不一致。
写在最后
缓存的本质不是"快",是**"让系统在流量暴涨时不要崩"**。
我一个2核4G的服务器,加上合理的缓存后,能扛住每秒200次请求。不加缓存的时候,30次就挂了。
对于微平台来说,缓存不是可选项——它是你一个人对抗整个互联网流量的盾牌。