Redis缓存系列之穿透、击穿、雪崩、预热、更新、降级

缓存穿透

当查询Redis中没有的数据时,该查询会下沉到数据库层,如果数据库层也无该数据,这种情况大量出现或被恶意攻击时,接口的访问会全部穿透Redis直接访问数据库,而数据库中也没有这些数据,我们称这种现象为"缓存穿透"。缓存穿透会穿透Redis的保护,提升底层数据库的负载压力,同时这类穿透查询没有数据返回也造成了网络和计算资源的浪费。

解决方案:

1、在接口访问层对用户做校验,如接口传参、登陆状态、n秒内访问接口的次数;
2、利用布隆过滤器(BloomFilter),将数据库层有的数据key存储在位数组中,以判断访问的key在底层数据库中是否存在;

注:布隆过滤器可以判断key一定不在集合内以及key极有可能在集合内。

基于布隆过滤器,我们可以先将数据库中数据的key存储在布隆过滤器的位数组中,每次客户端查询数据时先访问Redis。
如果Redis内不存在该数据,则通过布隆过滤器判断数据是否在底层数据库内。
布隆过滤器本身有误判,会出现判定有但实际无的情况。
但如果布隆过滤器判定某个key不存在,则一定不存在。

附:Redis Bloom Filter 相关操作

bf.add 添加元素到布隆过滤器
bf.exists 判断元素是否在布隆过滤器
bf.madd 添加多个元素到布隆过滤器,bf.add只能添加一个
bf.mexists 判断多个元素是否在布隆过滤器

参考链接:https://juejin.cn/post/6844903862072000526

缓存击穿

当热点数据key从缓存内失效时,大量访问同时请求这个key,就会将查询下沉到数据库层,此时数据库层的负载压力会骤增,这种现象称之为"缓存击穿"。

缓存雪崩

缓存雪崩是缓存击穿的"扩大"版,缓存雪崩是指Redis中大量的key几乎同时过期,然后大量并发查询穿过redis击打到底层数据库上,此时数据库层的负载压力会骤增,我们称这种现象为"缓存雪崩"。事实上缓存雪崩相比于缓存击穿更容易发生,同时超大并发量访问同一个过时key的场景的确太少见了,而大量key同时过期,大量用户访问这些key的几率相比缓存击穿来说明显更大。

解决方案:

1、在可接受的时间范围内随机设置key的过期时间,分散key的过期时间,以防止大量的key在同一时刻过期;
2、对于一定要在固定时间让key失效的场景(如,凌晨准时更新所有最热排名),可在固定的失效时间时在接口服务端设置随机延时,将请求的时间打散,让一部分查询先将数据做缓存;
3、延长热点key的过期时间或者设置永不过期。
4、增加互斥锁(后端语言+Lua+redis)

缓存预热

如字面意思,当系统上线时,缓存内还没有数据,如果直接提供给用户使用,每个请求都会穿过缓存去访问底层数据库,如果并发大的话,很有可能在上线当天就会宕机,因此我们需要在上线前先将数据库内的热点数据缓存至Redis内再提供出去使用,这种操作就成为"缓存预热"。
缓存预热的实现方式有很多,比较通用的方式是写个批处理任务,在启动项目时或定时去触发将底层数据库内的热点数据加载到缓存内。

缓存更新

缓存服务(Redis)和数据服务(底层数据库)是相互独立且异构的系统,在更新缓存或更新数据的时候无法做到原子性的同时更新两边的数据,因此在并发读写或第二步操作异常时会遇到各种数据不一致的问题。
缓存更新的设计模式有四种:
Cache aside:查询,先查缓存,缓存没有就查数据库,然后加载至缓存内;更新:先更新数据库,然后让缓存失效;或者先失效缓存然后更新数据库;
Read through:在查询操作中更新缓存,即当缓存失效时,Cache Aside 模式是由调用方负责把数据加载入缓存,而 Read Through 则用缓存服务自己来加载;
Write through:在更新数据时发生。当有数据更新的时候,如果没有命中缓存,直接更新数据库,然后返回。如果命中了缓存,则更新缓存,然后由缓存自己更新数据库;
Write behind caching:俗称write back,在更新数据的时候,只更新缓存,不更新数据库,缓存会异步地定时批量更新数据库;

推荐模式:Cache aside:
即:先失效缓存,后更新数据库,配合延迟失效来更新缓存的模式。

为了避免在并发场景下,多个请求同时更新同一个缓存导致脏数据,因此不能直接更新缓存,而是设置先让缓存失效。
先失效缓存后更新数据库:并发场景下,推荐使用延迟失效。比如写请求开始前给缓存设置1s过期时间,然后再去更新数据库的数据,此时其他读请求仍然可以读到缓存内的数据,当数据库端更新完成后,缓存内的数据已失效,之后的读请求会将数据库端最新的数据加载至缓存内保证缓存和数据库端数据一致性;
在这种方案下,第二步操作异常不会引起数据不一致,例如设置了缓存1s后失效,然后在更新数据库时报错,即使缓存失效,之后的读请求仍然会把更新前的数据重新加载到缓存内。

缓存降级

缓存降级是指当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,采取有损于不重要的非核心服务的方式,来保证主服务可用。
通过对其他次要服务的数据进行缓存降级,从而提升主服务的稳定性。
降级目的:是保证核心服务可用,即使是有损的。
如某年双十一的时候淘宝购物车无法修改地址只能使用默认地址,这个服务就是被降级了,阿里保证了订单可以正常提交和付款,但修改地址的服务可以在服务器压力降低,并发量相对减少的时候再恢复。
降级可以根据实时的监控数据进行自动降级也可以配置开关人工降级。

注:是否需要降级,哪些服务需要降级,在什么情况下降级,都需要考虑进去。

你可能感兴趣的:(Redis缓存系列之穿透、击穿、雪崩、预热、更新、降级)