缓存穿透
- 描述 向服务器端查询一个不存在的数据,redis缓存和数据库层均不能命中,导致每次请求都需要去数据库层去查询。
- 解决方案
- 缓存空对象
- 布隆过滤器(存在时不一定存在,不存在时一定不存在) 先由布隆过滤器过滤一遍,基本可以解决缓存穿透问题。
缓存雪崩
- 描述 大量缓存同一时间失效,有可能会导致大量请求同时穿透缓存去查询数据库,使数据库压力过大。
- 解决方案
将缓存失效时间设置成 固定时间+随机时间, 比如:
100ms + random(100)
缓存击穿
- 描述 数据存在于数据库中,但不存在于缓存中,通常是因为缓存中的那份数据已经过期。
- 解决方案
- 设置热点数据永远不过期
- 加互斥锁
热key问题
- 描述 抢购场景下(比如小道消息获取到商品值得购买),大量请求同时访问同一数据,因缓存不存在,请求直接访问到数据库层。
- 解决方案 使用redis的分布式锁解决, 只允许一个线程去重建缓存。
# 伪代码
public String getData(String key) {
String data = getCache(key);
if (null == data) {
if (getLock(key)) {
data = queryDB(key);
saveCache(data);
freeLock(key);
} else {
sleep(20);
data = getData(key);
}
}
return data;
}
缓存和数据库双写不一致
- 两种情况:
- 解决方案(需要强一致性)
- 使用读写锁
- 使用canal监听数据库的binlog及时修改缓存
bigkey
问题
- 描述
指value占用的内存空间比较大。字符串类型最大为512m,其他数据类型最多存储
2^32 - 1
个元素。 字符串大小大于10Kb或者其他数据类型元素个数超过5000就认为是bigkey
。 - 危害
- 造成redis阻塞
- 网络拥塞
- 过期删除时会导致redis阻塞, 采用渐进式(hscan, sscan, zscan)删除。