缓存穿透、缓存击穿以及缓存雪崩的含义和解决方案

前言

Redis在目前的分布式系统中是比较常用的一个缓存中间件,但实际应用中,经常会遇到缓存穿透、缓存雪崩等问题,那么什么是缓存穿透、缓存击穿、缓存雪崩呢?三者之间有什么联系和区别呢?实际应用中有什么解决方案呢?

为什么要使用Redis?

项目中可能会遇到MySQL: ERROR 1040: Too many connections”的异常情况,造成这种情况的一种原因是访问量过高,MySQL服务器抗不住,这个时候就要考虑增加从服务器分散读压力;另一种原因就是MySQL配置文件中max_connections值过小。解决这个问题,那就有以下方案:

  • 增加MySQL连接数:MySQL支持的最大的连接数是512,增加连接数的前提是机器的性能能够跟得上,MySQL会为每个连接提供连接缓冲区,连接数越多就会开销越多的内存,所以要适当调整该值,不能盲目提高设值。
  • 分库分表:对数据库进行切分,减少单机数据库的负担,将由多台数据库服务器一起来分担,缩短查询时间,增加并发量,但是缺点是增加了查询某些数据的复杂度,比如order by 操作,分表后,数据分散到多个表中,排序操作无法在数据库中完成,只能由业务代码或数据中间件分别查询每个子表中的数据,然后汇总进行排序。
  • 增加缓存层:这是比较常用的解决方案,把一些热门数据放到缓存中,在客户端请求数据时,先查缓存中有没有想要的数据,有则直接返回,没有的话,再去MySQL中查询,这样就减轻了数据请求的压力。Redis自然是缓存中间件的首选。

Redis缓存穿透

在下图中,常见的数据查询过程中,客户端请求的数据在缓存中没有,进而去数据库中请求数据的现象就是缓存穿透。架构中使用了redis缓存层,就无法避免发生缓存穿透,但是可以避免发生高频的缓存穿透。
缓存穿透、缓存击穿以及缓存雪崩的含义和解决方案_第1张图片

布隆过滤器和布隆算法

什么情况下,会发生高频的缓存穿透呢?假如有人恶意请求一批数据库中不存在的id的数据,比如uuid,由于缓存中没有这些数据,那么这些请求就全部打向数据库,这样就给数据库带来很大的压力,有可能会造成数据库宕机。
对于上面这种场景,我们可以使用布隆过滤器来解决,请求先经过过滤器过滤,非法的请求直接被拒绝,如下图所示。
缓存穿透、缓存击穿以及缓存雪崩的含义和解决方案_第2张图片
但是这样会带来一个问题,布隆过滤器因为存放的资源比较多,会占用较多的内存,造成内存紧张,这时就需要布隆算法,它会通过一定的错误率来换取空间。

布隆算法的原理:其原理比较简单,如下图所示,S集合中有n个元素,利用k个哈希函数,将S中的每个元素映射到一个长度为m的位(bit)数组B中不同的位置上,这些位置上的二进制数均置为1,如果待检测的元素经过这k个哈希函数的映射后,发现其k个位置上的二进制数不全是1,那么这个元素一定不在集合S中,反之,该元素可能是S中的某一个元素。
缓存穿透、缓存击穿以及缓存雪崩的含义和解决方案_第3张图片
布隆过滤器是用来判断一个元素是否出现在给定集合中的重要工具,具有快速,比哈希表更节省空间等优点,而缺点在于由于哈希碰撞,有一定的误识别率(false-positive,假阳性),亦即,它可能会把不是集合内的元素判定为存在于集合内,不过这样的概率相当小,在大部分的生产环境中是可以接受的。

减少哈希碰撞的方案:

  • 增加bit数组的长度
  • 增加哈希函数的个数,注意并不是函数越多越好,需要参考数组的长度。

布隆算法在删除数据时存在一个弊端,可能数组的某一位为1对应着很多个id,不能轻易置为0,我们可以加个计数器,分别记录数组每个位置对应的id数,只有当计数为1时,删除该id可以置为0。

缓存雪崩和缓存击穿

缓存雪崩:缓存层中缓存的数据中某一个时刻突然失效,导致大量的请求直接打向数据库。
缓存雪崩发生原因:

  • redis中数据有效期一致,同时失效。解决方案:随机有效期,不让缓存同时失效
  • redis数据库宕机。解决方案:分布式缓存,将大量的数据分开存放,如切片集群模式,如果数据量不大,可以采用副本集群模式,多个Redis存放一样的数据。

缓存击穿:指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。

Redis集群的Hash一致性算法

对于切片集群模式的Redis集群需要存放数据时,可以采用Hash值取模的方法,来将数据分别存放到两个Redis数据库中,如下图所示,但是这种方式有一个缺点,当我集群进行扩展时,会存在数据迁移问题。
缓存穿透、缓存击穿以及缓存雪崩的含义和解决方案_第4张图片
更好的方案就是采用Hash一致性算法,简单来说先构造一个的整数环,然后将Redis服务器节点的Hash值,放在该环上。然后根据需要缓存的数据的Key,计算Key的HashCode,然后在环上,顺时针查找距离这个Key的Hash值最近的缓存服务器的节点,然后将Value,存储到该服务器节点上。如下图所示。
缓存穿透、缓存击穿以及缓存雪崩的含义和解决方案_第5张图片
如果发生数据倾斜,可以通过增加虚拟节点的方式解决。

总结

缓存击穿和缓存雪崩本质上都是缓存穿透,两者都是缓存穿透的特殊表现。

你可能感兴趣的:(Redis,redis,数据库,mysql)