redis缓存雪崩、缓存击穿、缓存穿透
作者:向前的步伐 / 发表: 2020年1月1日 21:35 / 更新: 2020年1月1日 21:37 / redis / 阅读量:664
redis缓存的使用,极大的提升了应用程序的性能和效率,特别是在查询数据方面。其中它也带来了一些问题,其中最要害的就是数据一致性问题,如果对数据的一致性要求很高,就不能使用缓存。另外也有一些典型的问题,就是缓存雪崩、缓存击穿、缓存穿透。目前业界也有一些流行的解决方案。
一、缓存雪崩
如果存在缓存中的key,在同一时间内,大量的缓存过期,原本访问缓存的请求全部都去查询数据库了,给数据库的CPU和内存造成了压力,严重的会造成数据库宕机,这就是缓存雪崩。
解决方案:
1,加锁排队
在缓存失效后,通过加锁或者队列来控制读写数据库的线程数量。可以使用redis的setnx去set一个mutex key,当操作返回成功时,再进行数据库的查询和缓存的回设,否则重试get缓存的方法。
2,数据预热
缓存预热就是系统上线之后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题。预先去更新缓存,在即将发生大并发访问前手动触发加载缓存。
3,双层缓存策略
cache1为原始缓存,cache2为拷贝缓存,cache1失效时,可以访问cache2,cache1缓存失效时间设置为短期,cache2缓存设置为长期。
4,定期更新缓存策略
实效性要求不高的缓存,容器启动初始化加载,采用定时任务更新或者移除缓存。
5,设置不同的过期时间,让缓存实效的时间点尽量均匀
不同的key,可以设置不同的过期时间,让缓存失效的时间点不一致,尽量达到平均分布。
二、缓存击穿
缓存中有一个key非常热点,在不停的扛着大量并发请求,当这个key失效的瞬间,持续的大并发请求穿破缓存,直接都请求数据库,就像在墙上打了一个洞,这就是缓存击穿。
解决方案:
缓存击穿的原因主要在多个线程同时去查询数据库这条数据,那么可以在第一条线程请求数据库的时候,使用一个互斥锁来控制它。其他线程遇到锁就不会同时请求数据库,当第一条线程获取到数据之后做缓存数据,后面的线程就可以直接在缓存中获取数据。
三、缓存穿透
用户查询数据库中没有的数据时,这时数据库没有,缓存自然也没有数据。这样就导致用户在缓存中查询不到数据,又去数据库查询一遍,然后返回空值,这样的请求就绕过了缓存直接请求数据库,这就是缓存穿透。
解决方案:
1,缓存空值
如果一个数据查询返回空(不管是数据不存在,还是系统故障),我们仍然把这个空数据结果存进缓存中,但它的过期时间会很短,最长不超过5分钟。通过这个设置的默认值存在到缓存,这样第二次到缓存就有值了,而不会继续请求数据库。
2,采用布隆过滤器
将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层数据库的查询压力。
在查询之前,先去布隆过滤器查询key是否存在,如果不存在就直接返回,存在再去查缓存,缓存没有再去查数据库。
优势:占用内存空间小,位存储;性能特别高,使用key的hash判断key存不存在。