概述
1.redis介绍
大家都知道,当我们项目中需要对外提供一些信息的时候,不可能让其他项目直连我们的数据库,那怎么办呢? 我们可以项目开放一个接口,提供被调用服务。但是,如果接口访问压力大,怎么办?我们一般引用缓存,用内存方式缓存耦合度比较高,并且不方便管理。此时,我们需要引入redis,redis很好的帮我们解决了这个问题,官网是这样介绍redis的。但是,如果我们对数据一致性要求比较高的话,使用缓存的话,就达不到要求的效果。
Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes with radius queries and streams. Redis has built-in replication, Lua scripting, LRU eviction, transactions and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster。意思大概就是:
Redis是开源的,数据存储在内存当中,用作数据库,缓存和消息代理。它支持数据结构有字符串,hash,列表,集合,带有范围查询的排序集,位图,超级日志,具有半径查询和流的地理空间索引。 Redis具有内置复制,Lua脚本,LRU驱逐,事务和不同级别的磁盘持久性,并通过Redis Sentinel提供高可用性并使用Redis Cluster自动分区。
2.缓存击穿
缓存击穿怎么理解?这个和缓存雪崩有些类似,但又有区别。针对redis里面的单个key,假如这个key被高并发的访问。同时,我们又设置了过期时间,大量的请求在缓存key失效的那一刻,请求到DB中,造成DB压力大,系统异常或者redis不可用。缓存击穿强调的是查询经过了缓存,而此时缓存刚好失效。
解决方案:
01:设置缓存永不过期。但是,假如说系统存在bug,数据库数据发生改变,缓存没有更新,造成脏数据,这个方案不是最佳方案。
02:加锁,下面我用代码给大家演示:
/**
* 获取value
*
* @param key
* @return
*/
@RequestMapping(value = "getValue")
public Object getValue(String key) throws InterruptedException {
Object result = null;
result = redisTemplate.opsForValue().get(key);
if (result == null) {
//说明缓存中不存在,请求DB,这里面查询数据库代码,我没有写,设置查询数据库需要10S
Thread.sleep(10000);
String resultValue="数据库返回结果";
//缓存时效时间
Long time=3000L;
//将数据库返回结果,存到缓存中
boolean resultSet=insertRedis("1",resultValue,time);
if(resultSet){
result=resultValue;
}
}
return result;
}
这里是我们常用的代码模式,假如数据不存在,去查询数据库,然后放到redis当中。但是我们有没有想过假如查询数据库耗时比较久,大量并发请求堆积在查询数据库中,会造成数据库压力过大,可能数据库被搞崩。 1:方法锁:不适合,这样虽然解决了问题,但是就无法处理并发了,如下图所示:
2:代码锁,缩小锁的颗粒度:这样就保证有且只有一个线程查询了数据库,其他线程都是从缓存中拿,这个针对于单个key并发请求,多个key的会在缓存雪崩中提到处理方式。
03:定时补偿任务:这个我说一下逻辑,我们项目单独开一个线程,监听redis里面数据失效时间,当数据<30S要失效的时候,我们去数据库将最新的数据查询出来,重新赋值redis,并赋值新的缓存失效时间。这样,我们key永久就不会过期,请求过来直接查redis,存在就有,不存在就是没有,不会有请求数据库的情况发生,这是用代码的逻辑去访问这个问题的发生。
2.缓存雪崩
缓存雪崩和缓存击穿类似。缓存雪崩指的是同一个redis数据库的key在同一时间过期,大量的请求,直连数据库查询,造成系统数据库压力过大。 这种解决的方式用缓存击穿的里面提供的方法可以也可以解决,但是这里提供了另外一种方式:
解决方案:
加随机范围时间。意思就是,我们在进行数据存入redis的时候,指定过期时间+随机的分钟,这样可以保证每一个数据都有不同的过期时间,根本不会出现大批量数据同一时间过期问题。
2.缓存穿透
缓存穿透指的是:大量恶意请求传入的key在redis和数据库中不存在,导致每次都要进行数据库查询,查询出来的值又是空的,而我们没有把空值保存在redis中,导致一直在做无用功。缓存穿透强调的是绕过缓存,直查的数据库。
解决方案:
将查询出来的空值,也保存在redis当中,保证不会一直大量请求系统数据库即可。
4.结束
以上方案可能只是部分解决方案,也有可能还有更好的实现方式和方法,欢迎大家一起交流。
最后
以上就是超帅猫咪为你收集整理的redis那些事之缓存击穿、缓存雪崩、缓存穿透的全部内容,希望文章能够帮你解决redis那些事之缓存击穿、缓存雪崩、缓存穿透所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复