redis:内存穿透、内存击穿、内存雪崩以及各数据类型应用场景

时间:2022-10-20 10:55:14

redis:内存穿透、内存击穿、内存雪崩以及各数据类型应用场景

redis:内存穿透、内存击穿、内存雪崩以及各数据类型应用场景

一、内存穿透(缓存穿透)

1.原因:

        redis存储数据类似于map集合是以键值对的形式进行存储数据,当用户输入查找的数据key首先在redis缓存数据库中进行查找,如果redis数据库中没有对应的key就会下层到数据库中执行sql代码在对应的数据库(例:mysql)中按照对应的where条件查询数据,如果最后在数据库中也没有找到对应的数据,则这就是redis内存穿透。缓存内存穿透会降低redis的系统保护,增大数据库服务器负荷以及浪费大量计算机和网络资源;

2.解决方法:

        思路:用户输入的查询名称(key)首先访问redis,就将名称与数据库中对应表所有的名称存入到一个集合中进行匹配。如果没有对应的名称就不需要进行数据库的查询,但如果数据过多的化将所有的名称取出存入到集合中也挺浪费资源;所以为了解决这个问题就需要采用到布隆过滤器的方法;

        布隆过滤器:采用哈希函数将一个元素映射位阵列的一个点上,然后将用户输入的名称进行对应匹配,最后如果点的数据全为0,则数据库中就一定不存在对应的查询名称,就不需要对数据库数据进行查询了;但如果为1,那么就很大概率的存在用户所需要查询的名称,在对数据库进行数据查询;从而很好的优化了redis的缓存穿透。

二、内存击穿(缓存击穿)

1.原因:

        一个长期没有被访问的数据或缓存时间到期的数据,从redis缓存数据库中删除时,然后又有大量的数据并发访问改数据时,就会访问到底层数据库,造成数据库服务器负荷量大幅度增加。

2.解决方法:

        将用户输入的第一个请求返回值为null时,就把该请求重新放到所有请求的尾部,其余的请求执行后返回值也为null时同样进行上面的操作。所有的请求都执行结束后,该请求又回到了请求队列的头部,这时就将该线程绑定一个互斥锁(互斥锁:同一时刻,只能执行一个线程)并进行数据库数据查找,其余的线程继续排队等待,当第一个线程完成查找后并把数据存入到redis缓存数据库中,后面的线程就重新访问redis数据库,重复上面的步骤,不直接访问数据库。

三、内存雪崩(缓存雪崩)

1.原因:

        雪崩与击穿相似,都是redis中数据过期删除数据记录导致大量访问直接到数据库中查询出现的的问题,但雪崩与击穿的不同点在于雪崩时大量的key从redis中过期导致的,然而击穿时个别极少量的数据过期从redis缓存数据库中删除导致的问题。

2.解决办法:

        1):在可接受时间范围内设置不同key的过期时间,防止大量的key在同一时段过期;

        2):与击穿相同设置互斥锁,在一时刻只能进行线程操作,其余等待,然后重复执行操作;

        3):使用双缓存策略,设置两个缓存,原始缓存和备用缓存,原始缓存失效时,访问备用缓存,备用缓存失效时间设置长点。

四、redis五种基本数据结构应用场景

1.字符串类型(String):

        常用命令:存储:set key value、获取:get key、删除:del key

        String存储key为String类型,其value不是String类型,是以二进制形式存储的,可以存储int型数据,以及图片或序列化对象等;

        应用场景:一般用于记录粉丝数量,用户数量等;

2.哈希表(hash):key-->value键值对集合,value实际就是一个HashMap

        常用命令:存储:hset key field value、获取:hget key field:获取指定的field对应的值、hgetall key:获取所有的field和value、 删除:hdel key field

       应用场景:一般用来存储Java对象,对应的id作为key,field作为属性的标签,value写入最后的属性值

3.列表(list):List 就是链表

可以添加一个元素到列表的头部或尾部  左(lpush)  右(rpush)

        常用命令:存储:lpush key value;   rpush key value、获取:lrange key start end :范围获取  lrange key 0 -1、删除:lpop key:删除列表最左边元素,并将元素返回、rpop key:删除列表最右边元素,并将元素返回

        应用场景:将Redis用作日志收集器,实际上还是一个队列,多个端点将日志信息写入Redis,然后一个worker统一将所有日志写到磁盘。取最新N个数据的操作:记录前N个最新登陆的用户Id列表,超出的范围可以从数据库中获得。在Redis中我们的最新微博ID使用了常驻缓存,这是一直更新的。但是我们做了限制不能超过5000个ID,因此我们的获取ID函数会一直询问Redis。只有在start/count参数超出了这个范围的时候,才需要去访问数据库。

4.set集合(其中元素唯一,不能重复存储):set 的内部实现是一个 value永远为null的HashMap

        常用命令:存储:sadd key value、获取:smembers key:获取set集合中所有元素、删除:srem key value::删除set集合中的指定元素

        应用场景:在微博中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis还为集合提供了求交集、并集、差集等操作,可以非常方便的实现如共同关注、共同喜好、二度好友等功能,对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。

5.zset集合(sorted set:有序集合,且元素不能重复)

        常用的命令:存储:zadd key score value、获取:zrange key start end、删除:zrem key value

        应用场景:Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择sorted set数据结构,比如twitter 的public timeline可以以发表时间作为score来存储,这样获取时就是自动按时间排好序的。和Set相比,Sorted Set关联了一个double类型权重参数score,使得集合中的元素能够按score进行有序排列,redis正是通过分数来为集合中的成员进行从小到大的排序。

        排行榜 、带权重的消息队列