文章目录
缓存穿透(查不到)
概述
缓存穿透简单记忆就是查不到,造成的问题是缓存数据库失去了抗一点流量的作用。现象是请求了一个redis中没有的key,也就是缓存没有命中,于是请求就会打到数据库,发现数据库也没有,查询就失败了。当很多请求同时进来,都会打到数据库上,给数据库造成很大的压力。
解决方案
通过概述可以知道缓存穿透造成的问题是缓存数据库失去了原来的作用,常见解法有以下两种:
布隆过滤器
布隆过滤器是一种hash结构,它的解法是先把数据库里有的key先添加到布隆过滤器中,在控制层先进行校验,不符合直接就抛弃请求,这样请求就不会打到redis。它对比传统的Map,Set等结构占用内存更小,更高效。
缓存空对象
这个在查不到key的时候通过缓存一个空对象来解决绕过缓存查数据库这一过程。但是需要注意是这个key需要一个过期时间,这样可以避免真实数据后续查不到的情况。
虽然解决了绕过缓存查数据库的问题,但是缓存空对象增加了存储成本,如果是恶意攻击就会产生很多没用的key。另外如果对数据有一致性要求的,在缓存过期时间内会有一段窗口的不一致。
缓存击穿(量太多了)
概述
缓存击穿是指一个热点key,在不停的扛着大并发,造成的问题是在key失效的瞬间,持续的大并发就穿破缓存,请求直接打到数据库,就像在一个屏障上凿开了一个洞。
当热key在过期的瞬间,需要去数据库库查数据重新缓存,这时持续的大并发会同时访问数据库来查询最新数据,并且回写缓存,会导使数据库瞬间压力过大。
解决方案
定时更新
可以通过定时任务定时去数据库查数据更新到缓存中并设置新的过期时间(续期),需要注意定时的时间间隔要小于过期时间,保证每次缓存都能查到数据。
设置热点数据永不过期
在业务允许的情况下可以不设置过期时间,所以不会出现热点key过期后产生的问题。后续在活动结束后可以手动删key。
加互斥锁
说得通俗点,就是如果在Redis里找一个键(key)对应的值(value)发现是空的,就先给它上个锁,接着从数据库里把这个值取过来,等东西拿全了,再把锁打开。这时候,如果有其他程序线程也想来找这个键的值,看到锁挂着呢,就只好排队等着了。我们用一个大家都能认的分布式锁来确保每个键同一时间只有一个人能去数据库拿信息,其他人就老实等着。这样做虽然能把好多同时来的请求压力分给分布式锁去处理,但也就意味着这把锁得特别能扛事儿,不然就成瓶颈了。
缓存雪崩(雪山崩了,没有一片雪花是无辜的)
概念
**缓存雪崩,是指在某一个时间段,缓存集中过期失效或Redis宕机。****缓存雪崩造成的问题是所有的请求都会达到数据库,数据库的调用量会暴增,造成数据库也会挂掉的情况。**原因是缓存没有了数据,所有请求都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰,打垮数据库。
其实缓存集中过期,不是最致命的,比较致命的缓存雪崩,是缓存服务器某个节点宕机或断网。因为缓存集中过期造成的缓存雪崩,一般是在某个时间段集中创建缓存,此时查一遍数据库就可以恢复,数据库也是可以顶住压力的,无非就是对数据库产生周期性的压力而已。而缓存服务节点的宕机,对数据库服务器造成的压力是不可预知的,很有可能瞬间就把数据库压垮。
解决方案
redis高可用
这个思想的含义是,既然redis有可能挂掉,那我多加几台redis,其实就是搭建的集群。**这是最典型的方案,集群避免单点故障。**另外像双十一的时候可以考虑停掉一些服务来提高核心服务的高可用,比如停掉退款等服务
预热设置不同过期时间
数据预热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间带点尽量均匀
限流降级
这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如某一个key只允许一个线程查询数据和写缓存,其他线程等待。类似于互斥锁