关于【缓存穿透,缓存击穿,缓存雪崩,热点数据丢失】问题的解决方案
本篇文章转载自:石衫的架构笔记 微信公众号
前言
当我们系统中使用到了缓存时,不管是一级缓存还是多级缓存,它的作用就是业务系统在请求数据时,如果缓存中有,就从缓存中获取;如果缓存中没有,再去访问DB,从而减少DB的压力,缩短获取数据的时间。那么在使用缓存的过程中,会出现哪些常见问题?我们又如何来解决?
1 缓存穿透
1.1 什么是缓存穿透
正常情况下,我们去查询数据都是存在的。
那么请求查询一条压根在数据库中就不存在的数据,即在缓存和数据库中都没有这条数据,但是请求每次在缓存中找不到,就去访问数据库,比较占用和消耗数据库的资源,这种现象,就叫做缓存穿透。
1.2 穿透带来的问题
黑客攻击系统,通过缓存穿透,使用一个不存在的id,大量访问系统的接口,系统因为缓存中没有数据,而去大量的访问数据库,导致数据库资源被无效占用,影响甚至拖垮正常业务。
1.3 解决办法
1.3.1 缓存空值
我们知道,缓存服务器(redis)一般是通过key value来存储缓存数据的。当有请求过来,会通过key在缓存中查找数据。而发生缓存击穿的问题,是因为缓存服务器中没有存储这些无效数据的key,从而导致无效请求访问到数据库。
那么我们可以在这些请求访问数据库后,没有得到查询结果时,在缓存服务器中存储这个key,并设置它的值为null,这样当再次发生查询这个key的请求时,缓存服务器就直接返回null,不去访问数据库了。
但是不要忘记,设置缓存失效时间,方便正确数据的录入和更新。
1.3.2 BloomFilter
BloomFilter类似于一个hbase set用来判断某个元素(key)是否存在于某个集合中。
这种方式在大数据应用场景比较多,比如Hbase(HBase是一个分布式的、面向列的开源数据库)中使用它去判断数据是否在磁盘上。还有在爬虫场景判断url是否已经被爬取过。
这种方式可以加在第一种方案中,在缓存之前再加一层BloomFilter去查询key是否存在,如果不存在直接返回,存在再去查询缓存或者DB。
1.4 如何选择
针对大量恶意请求攻击,如果key重复多,使用第一种方案是有效的。
如果恶意请求key不重复的多,则使用第二种方案最有效。
2 缓存击穿
2.1 什么是缓存击穿
在平常高并发的系统中,大量的请求同事查询到一个key时,此时这个key正好失效了,就会导致大量的请求都转到数据库上面了,这种现象我们成为缓存击穿。
2.2 会带来什么问题
会造成数据库访问量突然增大,压力剧增。
2.3 如何解决
上面的现象是多个线程同时去查询数据库的这条数据,那么我可以在第一个查询数据的请求上使用一个 互斥锁 来锁住它。
其他的线程走到这一步拿不到锁就等待,等到第一个线程查询到了数据,然后做缓存,后面的线程进来发现已经有缓存了,就可以直接获取缓存,而不访问数据库了。
3 缓存雪崩
3.1 什么是缓存雪崩
在当某一时刻发生大规模的缓存失效的情况,比如你的缓存服务宕机了,会有大量的请求直接请求数据库上,结果数据库就撑不住了,也跟着挂掉了。
3.2 解决办法
3.2.1 事前:
使用集群缓存,保证缓存服务器的高可用。
比如使用redis,就要考虑到 主 从 + 哨兵和 集群 来避免redis的全面崩盘的情况。
3.2.2 事中:
ehcahe本地缓存 + Hystrix限流&降级,避免DB被打死
使用ehcahe本地缓存的目的也是考虑在redis集群完全不可用的时候,ehcahe本地缓存还能支撑一阵。
使用Hystrix进行限流&降级,比如一秒来了5000个请求,我们假设只能有一秒2000个请求通过这个组件,那么其他3000个请求就会走限流逻辑。
然后去调用我们自己开发的降级组件,比如设置一些默认值之类的,以此来保护DB不会被大量请求搞的宕机。
3.2.3 事后:
开启redis的持久化机制,恢复缓存服务器集群
缓存服务器重启,根据配置的持久化策略,会读取日志文件,恢复内存中的数据。
4 解决热点数据集中失效的问题
我们在设置缓存的时候,一般也会设置缓存的失效时间,过了这个时间,缓存失效了。
如果这批数据,是请求量比较高的,那么请求就会转到数据库去,数据库压力瞬间增大,性能下降甚至宕机。
就是缓存击穿现象。
4.1 解决办法
4.1.1 设置不同的失效时间
避免热点数据集中失效,在设置缓存时间时,我们让它们的失效时间错开。比如在一个基础的时间上加上或减去一个范围内的随机值。
4.1.2 互斥锁
结合上面提到的请求,在高并发请求中,在第一个请求去查询数据库的时候对它加一个互斥锁,其余的查询请求都会被组塞住,直到锁被释放,从而保护数据库。
但是也是因为它会阻塞其他线程,系统的吞吐量也会下降,需要结合业务中的实际需要来考虑要不要这么做。
(adsbygoogle = window.adsbygoogle || []).push({});
- 关于缓存穿透,缓存击穿,缓存雪崩,热点数据失效问题的解决方案
- redis缓存穿透、缓存雪崩、缓存击穿(热点Key)解决方案
- 缓存穿透,缓存击穿,缓存雪崩解决方案分析
- Redis缓存雪崩、缓存穿透、热点Key解决方案和分析
- 缓存穿透,缓存击穿,缓存雪崩解决方案分析
- 缓存穿透,缓存击穿,缓存雪崩解决方案分析
- 缓存穿透,缓存击穿,缓存雪崩解决方案分析
- 缓存穿透,缓存雪崩,缓存击穿解决方案分析
- 缓存穿透,缓存雪崩,缓存击穿的解决方案
- 缓存穿透、缓存击穿、缓存雪崩解决方案分析
- 关于Redis中缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等概念的入门及简单解决方案
- 缓存穿透,缓存击穿,缓存雪崩解决方案分析
- 缓存穿透,缓存击穿,缓存雪崩解决方案分析
- 缓存穿透,缓存击穿,缓存雪崩解决方案分析
- 缓存穿透,缓存击穿,缓存雪崩解决方案分析
- 【转载】缓存穿透,缓存击穿,缓存雪崩解决方案分析
- 学习笔记:cache 和spring cache 技术---本地缓存-分布式缓存,缓存穿透,雪崩,和热点key的问题
- 缓存穿透,缓存击穿,缓存雪崩解决方案分析
- 缓存穿透,缓存击穿,缓存雪崩解决方案分析
- 缓存穿透,缓存击穿,缓存雪崩解决方案分析