造城中·📚30 篇造城日记·📝最近更新:2026年07月11日

缓存策略:Redis的正确打开方式

2核4G的服务器,加缓存能扛200QPS,不加缓存30就挂。缓存不是"快",是"不崩"。

水哥
2026-06-038 分钟阅读

缓存不是"加个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次就挂了。

对于微平台来说,缓存不是可选项——它是你一个人对抗整个互联网流量的盾牌。

相关文章