Java 社招高频题:Redis 热点 Key 到底怎么破?

30 阅读4分钟



大家好,我是 31 岁的小米。今天这篇文章,想给你讲一个数据库被抢光鸡蛋的大爷大妈围殴的故事。

别急,这不是段子,这是一次真实到不能再真实的缓存事故,而且几乎是 Java 社招必考题

故事开场:超市打折,鸡蛋成了“热点 Key”

先给你一个画面。凌晨 0 点,某大型超市开始搞促销:

鸡蛋 1 块钱一斤,限量 1000 份

你是技术负责人,系统架构大概是这样:

  • Redis:负责缓存商品信息
  • MySQL:真实库存和商品数据
  • Java 服务:对外提供查询接口

为了扛住流量,你早早就把商品信息缓存进了 Redis。

  • key: product:egg:info
  • value: 商品详情 + 库存信息
  • TTL: 10 分钟

一切看起来都很完美。

事故发生:Key 过期的那一秒

问题就出在这 10 分钟后。发生了什么?

  • product:egg:info刚好过期
  • 恰好是 0 点整
  • 恰好有 10 万并发请求 同时进来

于是,系统内部发生了这样一段对话:

  • Java 服务 A:Redis 没数据了,我去查 DB
  • Java 服务 B:Redis 没数据了,我也去查 DB
  • Java 服务 C:Redis 没数据了,我也去查 DB
  • ……
  • MySQL:????你们要干嘛?

结果呢?

  • Redis 是空的
  • 所有请求同时打到 DB
  • 数据库连接池被打满
  • CPU 飙升
  • 服务雪崩式超时

你在监控面板前,心率比双十一还高。

这道面试题,本质考的是什么?

面试官一般不会跟你讲故事,他会冷冷地问你一句:

“Redis 的热点 Key 问题你怎么解决?”

这道题,表面上问 Redis,本质上考 4 件事

什么是「缓存热点 Key」?

我们先给它一个面试级定义

热点 Key:在某一时间段内,被大量并发请求频繁访问的缓存 Key,一旦失效或不存在,会导致请求集中打到后端 DB。

结合我们故事里的鸡蛋:

  • 商品信息访问量极高
  • 所有请求都读同一个 Key
  • Key 一旦过期,DB 就成了“公共厕所”

为什么热点 Key 会压垮 DB?

  • 正常流程(理想情况): 请求 → Redis 命中 → 返回
  • 热点 Key 失效时的真实流程: 请求 → Redis miss → 查 DB → 写 Redis → 返回

并发下的问题

N 个请求同时 Redis miss

  • N 次 DB 查询
  • N 次写缓存

这在并发世界里,有个名字:Cache Stampede(缓存击穿)

对缓存查询加锁(核心方案)

这是你在题目里已经给出的方案,也是最经典、最常考、最容易落地的方案

思想一句话总结:只允许一个请求去查 DB,其它请求等着

就像超市里:

  • 只允许一个人去仓库拿鸡蛋
  • 其他人排队
  • 拿回来后,大家一起分

实现思路拆解(面试必会)

伪代码流程

Java + Redis 实战代码示例

使用 Redis SETNX 实现分布式锁

为什么一定要 Double Check?

这是面试官特别爱追问的一点。如果不 Double Check 会怎样?

场景:

  1. 线程 A 拿到锁
  2. 查 DB,写缓存
  3. 线程 B 刚好等待结束
  4. 线程 B 不检查缓存,又去查 DB

于是:

  • DB 又被打了一次
  • 锁白加了

Double Check 的本质:防止锁内重复查 DB

锁方案的优缺点分析(表格必考)

如果面试官继续追问怎么办?

他可能会问:

“如果锁竞争非常激烈怎么办?”

你可以这样答(加分版):

1、锁 + 本地缓存

  • 锁内查 DB
  • 写 Redis
  • 同时写 JVM 本地缓存(Caffeine)

2、永不过期 + 异步更新

  • Key 永不过期
  • 后台定时异步刷新

3、提前预热热点 Key

  • 活动开始前
  • 主动写缓存
  • 避免第一次 miss

用一句话在面试中收尾(建议背下来)

“热点 Key 的核心问题不是 Redis,而是并发请求在缓存失效瞬间对 DB 的冲击,解决思路是通过互斥控制,让只有一个请求回源 DB,其它请求等待缓存构建完成。”

说完这句话,面试官一般会点头。

END

很多同学问我:“这些场景真的会发生吗?”

我想说一句很现实的话:只要你做过促销、秒杀、榜单、首页推荐,热点 Key 一定会发生。

缓存从来不是加了就完事,缓存失效的那一秒,才是真正考验系统设计的时候。

好朋友们,我们下篇见。

我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!