本文目录导读:

这是一个非常经典的面试题,也是高并发系统设计中必须考虑的问题。
核心理解:
- 缓存穿透:指查询一个根本不存在的数据,由于缓存中不命中,请求直接打到数据库,而数据库里也没有这条记录,导致每次查询都穿透缓存直达数据库。
- 后果:如果有人恶意攻击,大量请求“不存在的数据”(比如不断请求
user_id=-1或随机ID),数据库会因承受巨大压力而崩溃。
缓存穿透的四大解决方案
以下是业界最常用的解决方案,按推荐程度和适用场景排序。
缓存空对象(最常见、最直接)
这是最基础也最容易实现的方法。
- 做法:当数据库查询结果为空时,仍然将这个“空结果”(如
null、、特殊标记)缓存起来,并设置一个较短的过期时间(30-60 秒)。 - 优点:实现简单,能有效防止大量相同“不存在 key”的请求穿透。
- 缺点:
- 需要存储大量空值,浪费缓存空间。
- 如果过期时间设置不当,可能导致一段时间内数据和数据库不一致(比如数据刚被写入数据库,但缓存中的空对象还没过期)。
代码示例(伪代码):
public User getUserById(String userId) {
// 1. 从缓存获取
User user = cache.get(userId);
if (user != null) {
return user;
}
// 2. 缓存未命中,查数据库
user = dao.getUserById(userId);
// 3. 关键步骤:无论数据库有没有,都写入缓存
if (user == null) {
// 缓存空对象,设置短过期时间(例如30秒)
cache.set(userId, new User(), 30);
} else {
cache.set(userId, user, 3600); // 正常数据缓存1小时
}
return user;
}
布隆过滤器(最优雅、最彻底)
在请求到达缓存层之前,先用布隆过滤器判断 key 是否可能存在。
- 做法:将数据库中所有存在的 key(如用户ID)预加载到布隆过滤器中,当一个请求来时,先检查过滤器。
- 如果布隆过滤器说“不存在”,则直接返回“数据不存在”,根本不去查询缓存或数据库。
- 如果布隆过滤器说“存在”,再去查询缓存或数据库。
- 优点:内存占用极低(几百万数据只占几十MB),查询速度极快(O(1)),能100%拦截不存在的 key 对后端的冲击。
- 缺点:
- 存在误判率(布隆过滤器说“存在”时可能不存在,但说“不存在”时一定不存在),业务上可以接受少量误判。
- 数据更新时需要同步更新布隆过滤器,维护成本略高(可以使用布谷鸟过滤器或分段布隆过滤器来解决)。
- 典型场景:新闻推荐、用户ID校验、防止重复爬虫。
接口校验(前端防御)
将非法请求拦截在业务逻辑之前。
- 做法:
- 对用户输入进行严格的合法性校验(如 ID 格式、长度、是否为负数等)。
- 对于敏感数据(如ID为0或负数),直接返回错误,不继续查询。
- 场景:简单有效,但无法防御所有攻击(比如请求一个根本不存在的合法格式的ID,如
user_id=999999)。
热点参数限流/降级
在高并发场景下作为兜底方案。
- 做法:监控数据库查询频率,如果发现某个 key 的数据库QPS(每秒查询率)异常升高,对该 key 的请求进行限流或熔断,返回默认值或降级信息。
- 场景:防止恶意攻击打垮数据库,但属于“治标不治本”,一般配合上述方案使用。
方案对比与选择
| 方案 | 适用场景 | 复杂度 | 内存占用 | 防御效果 | 主要缺点 |
|---|---|---|---|---|---|
| 缓存空对象 | 通用,小规模系统、数据量不大 | 低 | 高(存很多空key) | 拦截重复穿透 | 浪费内存,有短暂不一致 |
| 布隆过滤器 | 大规模系统、高并发、数据量级大 | 中 | 极低 | 彻底拦截(零漏网) | 有误判率,需数据同步 |
| 接口校验 | 任何系统,作为辅助 | 低 | 无 | 拦截明显恶意请求 | 无法防御合法格式的不存在ID |
| 限流/降级 | 兜底方案,保护数据库 | 高 | 低 | 被动防御 | 影响正常用户 |
面试回答建议
当面试官问这个问题时,建议按以下逻辑回答,展现你的思考深度:
- 先定义问题:“缓存穿透指的是查询一个不存在的数据,导致请求绕过缓存直接打到数据库,如果并发高,数据库可能瞬间被打爆。”
- 提出解决方案,按推荐顺序:
- “最直接的办法是缓存空对象,即使数据库没有,也缓存一个空结果并设置短过期时间,这能解决大部分问题,但会消耗缓存空间。”
- “更优的方案是使用布隆过滤器,在应用启动时,将数据库所有主键加载到布隆过滤器中,请求到达时先判断 key 是否在过滤器中,如果不存在,直接拒绝,这种方法内存占用极低,能从根本上拦截穿透。”
- “接口层做参数校验(比如ID格式、范围)是必须的,可以在布隆过滤器之前再拦截一层恶意攻击。”
- 结合业务场景说明:“如果业务数据量巨大(比如上亿用户ID),我会优先选择布隆过滤器;如果业务数据量较小或者团队想快速上线,可以先采用缓存空对象,后续再优化为布隆过滤器。”
这样的回答既能体现你对技术原理的掌握,也能展示你根据场景权衡利弊的工程思维。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播