一、正常情况
正常情况下的流程是这样的,先查缓存,缓存无就查数据库。
二、缓存雪崩
缓存雪崩是指缓存中的数据大批量的过期 ,而查询量巨大,造成数据库压力过大而崩溃。
1、解决方法
- 尽量保证redis集群的高可用性,当发现机器坠机时尽快补上。
- 选择合适的缓存淘汰策略。
- 缓存的过期设置随机时间,防止大量数据同时过期。
- 利用redis持久化机制保存的数据尽快恢复缓存。
三、缓存击穿
缓存击穿是指缓存中没有数据,而数据库中有数据,一般是缓存中的数据过期了,然后很多用户并发查询该数据,同时在缓存中读取该数据没读取到,就同时去数据库中查,造成数据库压力过大。缓存击穿强调的是一个数据过期,同时并发去访问该数据;而缓存雪崩是强调大量的数据过期。
1、解决方法
- 设置热点数据永不过期。
- 加互斥锁。
互斥锁示例如下:
/**
* @Description: 使用互斥锁来获取数据
* @Author: caixucheng
* @Date: 2020/10/6 20:12
* @param key: key
* @return: java.lang.Object
* @version: v1.0.0
**/
public Object getData(String key) throws InterruptedException {
// 从缓存中获取key
Object res = getDataFormRedis;
if (res == null){
// 缓存中没有
// 尝试去获取锁
if (reentrantLock.tryLock()){
// 去数据库中查
res = getDataFormSql(key);
if (res != null){
// 写进缓存
updateDataRedis(key,res);
// 释放锁
reentrantLock.unlock();
}
}else {
// 暂停100ms再去获得锁
Thread.sleep(100);
res = getData(key);
}
}
return res;
}
四、缓存穿透
缓存穿透是指缓存中没有该数据,数据库中也没有该数据。而用户不断地发请求,比如不断发生一些id=-1
或者是根本就很不合理的数据来发生请求。这种一般是别人想攻击你。攻击会导致数据库压力过大。
大概流程变为如下:
1、解决方法
- 做好参数检验,对于一些不合理的数据判断后直接返回。
- 缓存无效key,当从缓存和数据库中都查不到某个key的数据,就将这个key写入缓存并设置过期时间。
- 使用布隆过滤器。当请求进来后,先用布隆过滤器判断当前请求的数据是否在布隆过滤器中,如果没有则返回,有则去向下请求缓存,缓存没有就去请求数据库。关于布隆过滤器可以看此文章:详解布隆过滤器,并教你自己实现一个布隆过滤器。