缓存雪崩、击穿、穿透

目录

前言

一、缓存雪崩

1.大量数据同时过期

1.均匀设置过期时间

2.互斥锁

3.后台更新缓存

2.Redis故障宕机

1.服务熔断或请求限流机制

2.构建Redis缓存高可靠集群

二、缓存击穿

1.设置互斥锁;

2.不给热点数据设置过期时间,由后台更新缓存。

三、缓存穿透

1.非法请求的限制

2.缓存空值或者默认值

3.使用布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在

布隆过滤器

总结


前言

用户的数据一般存在数据库,也就是磁盘里。

如果用户请求全访问数据库的话,数据库很容易崩溃,一般在他们中间回家一个Redis作为缓存层。(Redis是内存数据库,相当于数据缓存在内存里面,内存的读写速度比硬盘快好几个数量级,系统性能大大提升)

当缓存层出现异常的时候就可能遇到三个问题:

缓存雪崩、缓存击穿、缓存穿透。

一、缓存雪崩

有两种情况会出现缓存雪崩:

1.大量缓存数据同时过期

2.Redis故障

为了保证缓存中的数据和数据库中的数据一致性,会给Redis里的数据设置过期时间,当缓存数据过期后,用户访问的数据如果不在缓存里,业务系统需要重新生成缓存,因此就会访问数据库,并将数据更新到Redis里面,这样后续请求都可以直接命中缓存。

但是,当大量缓存数据在用一时间过期或者Redis故障宕机时,如果此时有大量的用户请求,都无法在Redis中处理,于是又全部都直接访问数据库,从而导致数据库的压力骤增,严重的会造成数据库宕机,可能造成整个系统崩溃,这就是缓存雪崩

1.大量数据同时过期

大量数据同事过期导致的缓存雪崩可以:均匀设置过期时间,互斥锁,后台更新缓存。

1.均匀设置过期时间

在缓存数据设置过期时间时,给这些数据的过期时间随机加上一个随机数,保证他们不会在同一时间过期。

2.互斥锁

在用户访问时加互斥锁,当用户访问的数据不在Redis里,加上互斥锁,保证同一时间内只有一个请求来构建缓存 (从数据库读取数据,再将数据更新到Redis里),当缓存构建完成后,再释放锁。如果有请求未能获取互斥锁,要么等待所释放后重新读取缓存,要么就返回空值或者默认值。

实现互斥锁的时候要设置超时时间,不然第一个请求拿到了锁,然后这个请求发生了某种意外而一直阻塞,一直不释放锁,这个时候其他请求也一直拿不到锁,整个系统就会出现无响应的现象。

3.后台更新缓存

缓存不设置有限期,而是让缓存永久有效,将更新缓存的工作交由后台线程定时更新。

这里也有一个问题。缓存不设置有效期并不是意味着数据能一直在内存里,因为当系统内存紧张的时候,有些缓存数据会被淘汰,而在缓存被淘汰到下一次后台定时更新缓存的这段时间内,业务线程读取缓存失败就返回空值,业务的视角就以为是数据丢失。

针对于业务视角的数据丢失问题,有两种解决方式。

1.后台线程不仅负责定时更新缓存,而且也负责频繁地检测缓存是否有效,如果检测到缓存失效了,马上从数据库中读取数据,并更新到缓存。(这个解决方式的检测时间间隔不能太长,太长也就导致用户获取的数据是一个空值而不是真正的数据,所以检测的间隔时间最好是毫秒级,但是总归是有个间隔时间,用户体验一般)

2.第二种方式就会好很多,因为它在业务线程发现缓存数据失效后,才通过消息队列发送一条消息通知后台线程更新缓存,后台线程收到消息后也要先去检测缓存是否存在,不存在才读取数据库数据,并将数据加载到缓存。(这方式的更新会更及时,用户体验提高)

缓存预热:在业务刚上线的时候,最好是提前把数据缓存起来,而不是等待用户访问才来触发缓存构建,就是缓存预热,后台更新缓存的机制刚好也适合干这个事情。

2.Redis故障宕机

常见的应对方式:服务熔断或者请求限流机制;构建Redis缓存高可靠集群。

1.服务熔断或请求限流机制

服务熔断机制:暂停业务应用对缓存服务的访问,直接返回错误。等到Redis恢复正常后,再允许业务应用访问缓存服务。

请求限流机制:服务熔断会导致全部业务都无法正常工作,请求限流机制的话,就只将少部分请求发送到数据库进行处理,再多的请求就在入口直接拒绝服务,等到Redis恢复正常并把缓存预热完后,在解除请求限流的机制。

2.构建Redis缓存高可靠集群

之前说的服务熔断或者请求限流机制是缓存雪崩发生后的应对方案,为了避免由于Redis故障宕机导致的缓存雪崩问题,最后通过主从节点的方式构建Redis缓存高可靠集群,如果Redis缓存的主节点故障宕机,从节点可以切换成为主节点,继续提供缓存服务。

二、缓存击穿

缓存击穿可以看成缓存雪崩的一个子集。

如果缓存中的某个热点数据过期了,此时大量的请求访问了该热点数据,就无法从缓存中读取,直接访问数据库,数据库很容易就被高并发的请求冲垮了。这就是缓存击穿的问题。

解决方式可以用到前面说的:

1.设置互斥锁;

2.不给热点数据设置过期时间,由后台更新缓存

三、缓存穿透

当用户访问的数据,既不在缓存中,也不在数据库中,没办法构建缓存数据。。。

当有大量这样的请求来到时,数据库的压力骤增。

一般由两种情况导致:业务误操作,导致缓存中的数据和数据库中的数据都被错误删除了,所以缓存和数据库中都没有数据;黑客恶意攻击,故意大量访问某些不存在数据的业务。

应对方案:非法请求的限制;缓存空值或者默认值;使用布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在。

1.非法请求的限制

在API入口处判断请求参数是否合理,比如请求参数是否含有非法制、请求字段是否存在,如果判断出是恶意请求就直接返回错误,避免进一步访问缓存和数据库。

2.缓存空值或者默认值

当线上业务发现缓存穿透的现象时,可以针对查询的数据,在缓存中设置一个空值或者默认值,这样后续请求就可以从缓存中读取到空值或者默认值,返回给应用,而不会继续查询数据库。

3.使用布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在

在写入数据库数据时,使用布隆过滤器做一个标记,然后在用户请求到来时,业务线程确认缓存失效后,可以通过查询布隆过滤器快速判断数据是否存在,如果不存在,就不用通过查询数据库来判断数据是否存在。

即使发生了缓存穿透,大量请求只会查询Redis和布隆过滤器,而不会查询数据库,保证了数据库能正常运行,Redis自身也是支持布隆过滤器的。

布隆过滤器

布隆过滤器有初始值都是0的位图数组和N个哈希函数两部分组成。当写入数据库数据时,在布隆过滤器里做个标记,这样下次查询数据是否在数据库时,就只要查询布隆过滤器,如果查询到数据没有内标记,就说明该数据就不在数据库中。

第一步,使用n个哈希函数分别对数据做哈希计算,得到n个哈希值;

第二步,将第一步得到的n个哈希值对位图数组的长度取模,得到每个哈希值在位图数组的对应位置。

第三步,将每个哈希值在位图数组的对应位置的之后设置为1。

比如,这个n可以设置为3,也就是如果一个数据存在,那么它在位图数组中有三个位置为1,查询时,只要判断这个数据对应的三个位置是不是都是1,只要有一个为0,就认为该数据不存在于数据库中。

当然,布隆过滤器会有哈希冲突的可能性,比如两个不同的数据,在相同的位置都是1,但是只存在其中一个数据时,就会存在误判的情况。

因此,查询布隆过滤器判断数据是否存在时,并不一定能证明数据库中存在这个数据,但是查询布隆过滤器不存在该数据时,那么,该数据就一定不在数据库中。

总结

过段时间我来再背一遍。 

什么是缓存雪崩、击穿、穿透? | 小林coding (xiaolincoding.com)

  • 19
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值