Redis缓存穿透 解析

Posted 干桂旭

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis缓存穿透 解析相关的知识,希望对你有一定的参考价值。

先解析一下Redis中什么叫做 缓存穿透

  正常情况下我们查询同一条数据会先到Redis缓存中查取,如果没有再到数据库中查询,如果同一时间几千个用户查询同一条数据,在第一个线程到数据库中查询到了还未来得及更新到Redis里时剩下的线程也同时到数据库中查询,就无法体现Redis缓存的目的,这样被称为 Redis缓存穿透,大批量请求直接到数据库中查询,很容易导致数据库直接奔溃。

 

我们看一下会导致缓存穿透的代码:

 #  redisConfig是我封装的一个类

# 请求到了这个service 先去的redis查询,查询不到才会去数据库查询,但是没有添加锁 故导致了 缓存穿透

@Override
public Student findStudent(String key) {
long l1 = System.currentTimeMillis();
log.info("先去redis里面去取...");
Student student = (Student) redisConfig.get("student-"+key);
if (null == student){
log.info("redis中没有查到,到数据库中去取...");
student = studentDao.getStudent(Integer.valueOf(key));
redisConfig.set("student-"+student.getId(),student);
long l2 = System.currentTimeMillis();
log.info("l2-l1:{}",l2-l1);
}
long l3 = System.currentTimeMillis();
log.info("l3-l1:{}",l3-l1);
return student;
}

# 我用Jmeter测试了一个高并发场景 从截图中可以看到 多个线程 多次到数据库中查询了

 

 

 

我们再看一下加了锁之后的代码:

# 也就再方法上加了一个  synchronized

@Override
public synchronized Student findStudent(String key) {
long l1 = System.currentTimeMillis();
log.info("先去redis里面去取...");
Student student = (Student) redisConfig.get("student-"+key);
if (null == student){
log.info("redis中没有查到,到数据库中去取...");
student = studentDao.getStudent(Integer.valueOf(key));
redisConfig.set("student-"+student.getId(),student);
long l2 = System.currentTimeMillis();
log.info("l2-l1:{}",l2-l1);
}
long l3 = System.currentTimeMillis();
log.info("l3-l1:{}",l3-l1);
return student;
}

# 如截图所示  只有第一次去数据库中查询  剩下的线程都到Redis中查询  从实测的效果来看 缺点就是性能太差

 

 

 

我们再看一下双层检测锁的代码:

# 在方法内部加 synchronized  synchronized 内部再查一下redis

@Override
public Student findStudent(String key) {
long l1 = System.currentTimeMillis();
log.info("先去redis里面去取...");
Student student = redisConfig.get("student-"+key);
if (null == student){
//双层检测锁
synchronized (this){
student = redisConfig.get("student-" + key);
if (null == student){
log.info("redis中没有查到,到数据库中去取...");
student = studentDao.getStudent(Integer.valueOf(key));
redisConfig.set("student-"+student.getId(),student);
long l2 = System.currentTimeMillis();
log.info("l2-l1:{}",l2-l1);
}
}
}
long l3 = System.currentTimeMillis();
log.info("l3-l1:{}",l3-l1);
return student;
}

# 同样也解决了Redis缓存穿透 的情况 性能会比在方法上添加 synchronized 好很多

 

 

 

总结:

 从如上代码中可以看到  如果要解决Redis数据穿透的问题  在方法内添加 synchronized 即可,建议使用双层检测锁  这样可以更大程度的保证性能;

以上是关于Redis缓存穿透 解析的主要内容,如果未能解决你的问题,请参考以下文章

Redis缓存击穿,缓存穿透,缓存雪崩解决方案(附代码)

Redis缓存穿透,缓存击穿,缓存雪崩解决方案以及封装Redis工具类

Redis缓存穿透,缓存击穿,缓存雪崩解决方案以及封装Redis工具类

Redis缓存穿透,缓存击穿,缓存雪崩解决方案以及封装Redis工具类

Redis 缓存穿透击穿和雪崩

redis缓存穿透,频繁查询db,怎么解决