Redis 三大缓存问题

Redis 三大缓存问题

缓存穿透 缓存击穿 缓存雪崩

1.缓存穿透

1.1 什么是缓存穿透

​ 缓存穿透,它就是指当用户在查询一条数据的时候,而此时数据库和缓存却没有关于这条数据的任何记录,而这条数据在缓存中没找到就会向数据库请求获取数据。它拿不到数据时,就会一直查询数据库,这样会对数据库的访问造成很大的压力。

​ 举个栗子:用户查询一个 id = -1 的商品信息,一般数据库 id 值都是从 1 开始自增,很明显这条信息是不在数据库中,当没有信息返回时,会一直向数据库查询,给当前数据库的造成很大的访问压力。

该如何解决这个问题呢?

缓存空对象(代码维护简单,但是效果不是很好)。
布隆过滤器(代码维护比较复杂,效果挺好的)。

1.2 问题解决

(1)缓存空对象

​ 缓存空对象它就是指一个请求发送过来,如果此时缓存中和数据库都不存在这个请求所要查询的相关信息,那么数据库就会返回一个空对象,并将这个空对象和请求关联起来存到缓存中,当下次还是这个请求过来的时候,这时缓存就会命中,就直接从缓存中返回这个空对象,这样可以减少访问数据库的压力,提高当前数据库的访问性能。

如果大量不存在的请求过来,那么这时候缓存岂不是会缓存许多空对象了吗~~~,如果时间一长这样会导致缓存中存在大量空对象,这样不仅会占用许多的内存空间,还会浪费许多资源呀。该如何解决呢?

设置一个过期时间

setex key seconds valule:设置键值对的同时指定过期时间(s)

(2)布隆过滤器

1.定义

​ 内部是使用bit数组的形式来进行key值的映射存储,使用hash进行存入的key的运算,得到bit数组的下标,然后将其下标对应的值改为1,在判断某个key存在不存在时,需要先对key进行hash运算,找到对应的下标,下标对应值为1,则存在,为0则不存在。

2.误判

​ 因为hash运算的结果会存在hash碰撞,导致运算后对应的bit数组的下标可能存在相同,所以会存在误判的现象但是,误判只会发生在,不存在的可能会误判为存在,存在不会误判为不存在

3.精确度

​ 和hash函数的个数以及数组的长度有关,
​ bit数组的长度越长,误判率就越低,
​ hash运算的个数越多,效率就越低,
​ hash运算的个数越少,误判率就越高,
​ 因此在使用时要从两者综合考虑。
布隆过滤器,默认错误率是 0.01 ,默认初始容量是 100,可以在初始启动的时候通过启动参数来进行配置

./redis-server ./redis.conf --loadmodule ./redisbloom.so INITIAL_SIZE 400 ERROR_RATE 0.004

4.删除

​ 因为可能存在hash碰撞,如果可以删除,则可能会导致删除的不是对应的数据,所以不存在删除

2.缓存击穿

2.1 什么是缓存击穿

​ 缓存击穿是指有某个key经常被查询,经常被用户特殊关怀,用户非常 love 它,也就类比“熟客” 或者 一个key经常不被访问。但是这时候,如果这个key在缓存的过期时间失效的时候或者这是个冷门key时,这时候突然有大量有关这个key的访问请求,这样会导致大并发请求直接穿透缓存,请求数据库,瞬间对数据库的访问压力增大。

归纳起来:造成缓存击穿的原因有两个。
(1)一个“冷门”key,突然被大量用户请求访问。
(2)一个“热门”key,在缓存中时间恰好过期,这时有大量用户来进行访问。

2.2 怎么解决

加锁。对于key过期的时候,在key要查询数据库的时候加上一把锁,这时只能让第一个请求进行查询数据库,然后把从数据库中查询到的值存储到缓存中,对于剩下的相同的key,则可以直接从缓存中获取结果。
​ 单机环境下:直接使用常用的锁即可(如:Lock、Synchronized等),分布式环境下可以使用分布式锁,如:基于数据库、基于Redis或者zookeeper 的分布式锁。

3.缓存雪崩

3.1 什么是缓存雪崩

​ 缓存雪崩是指在某一个时间段内,缓存集中过期失效,如果这个时间段内有大量请求,而查询数据量巨大,所有的请求都会达到存储层,存储层的调用量会暴增,引起数据库压力过大甚至宕机。

(1)Redis突然宕机

(2)大批缓存数据同一时间点失效

​ 举个栗子:我们基本上都经历过购物狂欢节,假设商家举办 23:00 - 24:00 商品打骨折促销活动。程序在设计的时候,在 23:00 把商家打骨折的商品放到缓存中,并通过redis的expire设置了过期时间为1小时。这个时间段许多用户访问这些商品信息、购买等等。但是刚好到了24:00点的时候,恰好还有许多用户在访问这些商品,这时候对这些商品的访问都会落到数据库上,导致数据库要抗住巨大的压力,稍有不慎会导致,数据库直接宕机。

3.2 怎么解决

(1) 高可用

​ redis有可能挂掉,搭建redis集群(一主多从或者多主多从),这样一台挂掉之后其他的还可以继续工作。

(2) 限流降级

​ 缓存失效后,通过加锁或者队列来控制读取数据库的线程数量,对某个key只允许一个线程查询数据和写缓存,其他线程等待。

(3) 数据预热

​ 数据预热,就是在正式部署之前,先把可能使用的数据预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。

(4) 不同的过期时间

​ 均匀的设置key的过期时间,尽量避免大量的key在同一时间点过期。

你可能感兴趣的:(redis,redis,缓存,java)