Redis持久化
由于Redis数据保存在内存中,所以突然断电会导致数据丢失,为了避免数据的丢失,就需要将数据保存到磁盘文件上。
持久化策略
AOF:默认每秒对数据进行持久化
RDB:按条件触发持久化操作,满足任意一个条件
①900 1 900秒中修改1次
②300 10 300秒中修改10次
③60 10000 60秒中修改10000次
也可以在redis.conf文件中手动配置
AOF:每秒都进行持久化操作,所以安全性比较高,对性能要求高
RDB:按条件进行持久化操作,所以安全性比较低,对性能要求低
这两种也可以一起用,一起用以后数据几乎不可能丢失
Redis淘汰策略
8种策略:
volatile-lru,针对设置了过期时间的key,使用lru算法进行淘汰。
allkeys-lru,针对所有key使用lru算法进行淘汰。
volatile-lfu,针对设置了过期时间的key,使用lfu算法进行淘汰。
allkeys-lfu,针对所有key使用lfu算法进行淘汰。
volatile-random,从所有设置了过期时间的key中使用随机淘汰的方式进行淘汰。
allkeys-random,针对所有的key使用随机淘汰机制进行淘汰。
volatile-ttl,删除生存时间最近的一个键。
noeviction(默认),不删除键,值返回错误。
主要是4种算法,针对不同的key,形成的策略。
算法:
lru 最近很少的使用的key(根据时间,最不常用的淘汰)
lfu 最近很少的使用的key (根据计数器,用的次数最少的key淘汰)
random 随机淘汰
ttl 快要过期的先淘汰
key :
volatile 有过期的时间的那些key
allkeys 所有的key
Redis并发问题与解决方案
1.雪崩
①Redis热点数据同时过期,大量请求全部打到MySQL,MySQL宕机
解决方法:将热点数据过期时间设置为随机值,避免同时过期
②单个Redis服务出现问题或重启
解决方法:配置Redis集群,解决单点故障问题
2.击穿
击穿大量并发请求访问Redis同一个数据,还没有向Redis保存,有大量线程同时访问,导致 MySQL压力过大
解决方法:通过双检锁实现线程同步执行
@Override
public Student getStudentById(Long id) {
//获得字符串操作对象
ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//先查询Redis
Student stu = (Student) ops.get(PREFIX + id);
if(stu == null) {
synchronized (this) {
System.out.println("进入了同步锁");
//先查询Redis
stu = (Student) ops.get(PREFIX + id);
//如果Redis缓存存在数据,就直接返回
if (stu != null) {
System.out.println("Redis查到,返回" + stu);
return stu;
}
//如果Redis没有查到数据,就查询MySQL
stu = studentMapper.selectById(id);
//MySQL查到数据,就保存到Redis
if (stu != null) {
System.out.println("MySQL查到,返回" + stu);
ops.set(PREFIX + id, stu);
return stu;
}
}
}else {
System.out.println("没有执行同步锁");
}
return stu;
}
3.穿透
大量请求访问MySQL没有的数据,Redis缓存无法命中,导致数据库压力过大
解决方法: 使用布隆过滤器筛选掉不存在的数据
public Student getStudentById(Long id) {
//获得字符串操作对象
ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//先查询Redis
Student stu = (Student) ops.get(PREFIX + id);
if(stu == null) {
synchronized (this) {
System.out.println("进入了同步锁");
//先查询Redis
stu = (Student) ops.get(PREFIX + id);
//如果Redis缓存存在数据,就直接返回
if (stu != null) {
System.out.println("Redis查到,返回" + stu);
return stu;
}
//使用布隆过滤器判断数据库中是否存在该id
if(rBloomFilter.contains(String.valueOf(id))) {
//如果Redis没有查到数据,就查询MySQL
stu = studentMapper.selectById(id);
//MySQL查到数据,就保存到Redis
if (stu != null) {
System.out.println("MySQL查到,返回" + stu);
ops.set(PREFIX + id, stu);
return stu;
}
}else{
System.out.println("布隆过滤器判断id数据库不存在,直接返回");
}
}
}else {
System.out.println("没有执行同步锁");
}
return stu;
}