缓存穿透、击穿、雪崩、预热、更新、降级

0x00:前言

Redis作为一款内存数据库,总会免不了出现各种各样的问题。

本篇文章首先将讲述 redis 在生产环境中会出现的三个问题:缓存穿透缓存击穿缓存雪崩

其次会稍微简述在高并发环境下常用的三个缓存操作:缓存预热缓存更新缓存降级


0x01:缓存穿透

什么是缓存穿透

要理解缓存穿透,我们首先需要了解一下正常情况下,Redis 是如何进行工作的

  1. 在用户请求查询数据时,程序首先会向Redis请求查询数据
  2. 如果在 Redis 数据库中找到了用户所需的那条数据,这会直接返回给程序,进而返回给用户
  3. 但是如果在 Redis 数据库中找不到这条数据,则会向下去持久层数据库(MySQL、Oracle)查询需要的数据
  4. 如果查询成功,则将数据直接返回给程序,并将其缓存至 Redis 数据库中;否则返回查询失败

Redis查询

这样看似非常合理,而且感觉不会出现什么奇怪的问题;

但是,当出现非常之多用户同时请求一条不存在的数据时,问题就出现了!

缓存穿透

若是用户们一直请求这一条不存在的数据,这相当于直接穿过 Redis 的防护,直接请求在持久层数据库上面,无端地增加了持久层数据库的压力,同时这类穿透查询没有数据返回也造成了网络与计算资源的浪费!这时若是遭到恶意攻击时,则很有可能造成持久层数据库宕机,从而导致服务崩溃。

解决方案

  1. 在接口层对用户进行校验,栗如:接口传参、用户登录状态,并设置限流,限制每秒接口访问次数
  2. 使用布隆选择器(BloomFilter),将持久层数据库中存在的数据 key 缓存在位数组中,以判断访问的 key 是否在持久层数据库中

布隆过滤器

  • 注意!布隆过滤器可以判断某个元素一定不存在,但是无法判断它一定存在!

基于布隆过滤器,我们可以先将数据库中存在的数据的 key 缓存在布隆过滤器中,每次用户查询数据时,优先访问 Redis 数据库

  • 如果 Redis 内不存在该条数据,则查询 布隆过滤器 判断所需数据是否存在于持久层数据库中
  • 如果 布隆过滤器 返回这条数据在持久层数据库中不存在,则直接返回数据不存在,而不会继续向持久层数据库查询数据
  • 如果 布隆过滤器 返回这条数据极有可能在持久层数据库中存在,那么将会继续向持久层数据库查询数据

使用 布隆过滤器 之后,能有效的将不必要的请求挡在 Redis 层,有效降低持久层数据库的压力


0x02:缓存击穿

什么是缓存击穿

缓存击穿和缓存穿透从名字上可能有点难以区分,因为它们俩只有一个字不同,而且字词意思都差不多。

但是,缓存穿透是 Redis 数据库与持久层数据库都没有数据造成的;而缓存击穿则是当热点数据从缓存内失效,而且持续保持着高访问且同时请求这个数据时,就会将查询请求发向持久层数据库,此时持久层数据库的负载压力会骤增,从而可能会引发数据库宕机,我们称这种现象为缓存击穿。

缓存击穿

解决方案

  1. 延长热点数据在 Redis 数据库的过期时间或者设置永不过期
  2. 添加 互斥锁 保证同一时刻只能有一个客户端可以到持久层数据库查询所需数据,一旦查到数据就更新缓存至 Redis 数据库中

添加互斥锁,同一时刻下,只能有一个客户端可以到持久层数据库中查询数据

添加互斥锁

若数据查询成功,则直接将数据返回并缓存至 Redis 当中,后续客户端直接由 Redis 直接返回;若查询失败,则返回查询失败,客户端释放当前锁,后续客户端重复前面的操作(获取锁、查询、释放锁)

查询解决


0x03:缓存雪崩

什么是缓存雪崩

缓存雪崩可以说是缓存击穿的加强版,不过缓存击穿是指同时并发查询同一条数据,而缓存雪崩则是不同的数据同时过期了,一时间都去持久层数据库查询数据,从而查询数据量巨大,引起数据库压力过大最后罢工宕机

缓存雪崩

解决方案

  1. 在可接受的时间范围内随机设置数据过期的时间,分散数据过期时间,以防止大量的数据在同一时刻过期
  2. 延长高热度数据的过期时间或者设置永不过期

0x04:缓存预热

缓存预热就是系统上线后,提前将相关的缓存数据直接加载到缓存系统。

避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!

缓存预热解决方案:

(1)写一个刷新缓存的脚本,上线前对相关数据进行预热缓存到Redis中

(2)数据量不大,可以在项目上线启动的时候,让程序自动预热加载

(3)设定定时任务,定时对缓存进行刷新


0x05:缓存更新

除了缓存服务器自带的缓存失效策略之外(Redis默认的有六种策略可供选择),我们还可以根据具体的业务需求进行自定义的缓存淘汰,常见的策略有两种:

(1)定时去清理过期的缓存;

(2)当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就去底层系统得到新数据并更新缓存。

两者各有优劣,第一种的缺点是维护大量缓存的key是比较麻烦的,第二种的缺点就是每次用户请求过来都要判断缓存失效,逻辑相对比较复杂!具体用哪种方案,大家可以根据自己的应用场景来权衡。


0x06:缓存降级

当项目的访问量剧增时,核心业务服务出现响应问题(响应缓慢&不响应)或非核心业务影响到核心业务性能时;可以在保证全部业务服务可以正常可用的情况下,对非核心业务的一些数据进行降级,也可以配置相关开关实现人工降级。

缓存降级的最终目的是保证核心业务服务可用,且不会影响用户体验,即使是有损的;但是有一些服务是不可被降级的(购物车业务、结算业务)。

在进行缓存降级之前需要对系统业务数据进行梳理,分析系统是否真的可以“弃卒保帅”;在分析的过程中,可以梳理出需要重要保护的数据,也可以分析出哪些数据可以被降级。


0x07:参考文档

阿里P8技术专家细究分布式缓存问题

Last modification:March 28th, 2021 at 12:49 am
给狐宝打点钱⑧