redis缓存雪崩、缓存穿透、缓存击穿与布隆过滤器

redis常见问题与布隆过滤器基础原理介绍

Posted by John Doe on 2020-11-02
Words 1.8k and Reading Time 6 Minutes
Viewed Times

前言

redis作为基于内存的非关系型数据库,通过读取缓存有效降低了大数据量访问系统(如购物商城网站)导致的数据库大量的磁盘读写操作,减少了数据库瘫痪、服务器宕机的风险。但是引入redis后也可能会产生新的问题导致redis缓存失效,大量数据访问依旧直接落在数据库上导致数据库瘫痪。本文主要介绍redis缓存雪崩、缓存穿透、缓存击穿与他们的解决方案。

redis常见问题

缓存雪崩

我们知道redis存储的数据大部分会设置过期时间这就导致有可能大量数据过期时间相近使得某时段大量缓存失效,又或者redis集群(即多台执行相同redis缓存服务的服务器群)宕机、重启导致服务器服务失效无缓存可用。想象一下,redis集群是高山积雪底层的雪堆,发生上述两大类问题后就如同积雪的底层不再起支持作用,大量的数据访问如雪崩一样冲向山下的数据库,这无疑让数据库离瘫痪、服务器宕机不远了。下图为避免雪崩的数据访问流程图。
避免缓存雪崩的系统设计访问流程图

解决方案:

  1. 设计上使用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。
    注意:加锁排队只是为了减轻数据库的压力,并没有提高系统吞吐量。假设在高并发下,缓存重建期间key是锁着的,这是过来1000个请求999个都在阻塞的。同样会导致用户等待超时

  2. 缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

雪崩处理:

发生前:尽量保证整个 redis 集群的⾼可⽤性,发现机器宕机尽快补上。选择合适的内存淘汰策
略。降低失效时间重复率。

发生中:错峰限流降低对数据库的访问量,避免数据库瘫痪。

发生后:使用redis持久化策略RDB(快照)、AOF(文件追加)的文件尽快进行缓存恢复。

缓存穿透

缓存穿透说简单点就是⼤量请求的key根本不存在于缓存中,导致请求直接到了数据库上,根本没有经过缓存这⼀层。举个例⼦:某个⿊客故意制造我们缓存中不存在的key发起⼤量请求,导致⼤量请求落到数据库。下图分别为正常读取缓存流程、缓存中不存在该key直接访问数据库、设置布隆过滤器过滤非法key的流程。
正常读取缓存流程
缓存中不存在该key直接访问数据库
设置布隆过滤器过滤非法key
解决方案:

  1. 上线前做好基本的参数校验,⼀些不合法的参数请求直接抛出异常信息返回给客户端。⽐如查询的数据库id不能⼩于0、传⼊的邮箱格式不对的时候直接返回错误消息给客户端等等。

  2. 请求redis读取缓存前添加布隆过滤器过滤非法的key,布隆过滤器可用判断该数据在数据库中是否存在从而避免非法和不存在的key去访问我们的数据库。下文详细介绍布隆过滤器。

  3. 设置缓存⽆效 key : 如果缓存和数据库都查不到某个 key 的数据就写⼀个key到 redis 中去并设置过期时间。这种⽅式可以解决请求的 key 变化不频繁的情况,如果⿊客恶意攻击,每次构建不同的请求key,会导致redis中缓存⼤量⽆效的key。很明显,这种⽅案并不能从根本上解决此问题。如果⾮要⽤这种⽅式来解决穿透问题的话,尽量将⽆效的 key的过期时间设置短⼀点⽐如 1 分钟。

缓存击穿

缓存雪崩和缓存穿透都理解的话,缓存击穿可以说是非常简单了。缓存击穿聚焦于热点的key数据,大并发集中对这些点进行访问,当这些热点数据发生过期失效可想而知持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。举个例子:电商网站上某个商品是爆款,一群用户访问这个商品信息结果这个商品信息的key在缓存中失效了,然后数据库就崩了,大家就都买不成了跑别的解决击穿问题的商城网站去买了。击穿的流程图可看上文缓存穿透流程图中缓存中不存在该key直接访问数据库的流程图。

解决方案:

  1. 业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。
    SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。

  2. 将热点数据的key直接设置过期时间特别长或永不过期自然解决,但注意这中不过期的key数据维护。

布隆过滤器

布隆过滤器(Bloom Filter)是一个数据结构,由布隆(Burton Howard Bloom)于1970年提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。
通俗的讲,布隆过滤器原理是将数据经过多次散列函数(几次取决于你的系统设置中对误差率的要求)将对应的二进制向量下标位置进行变1标注,当数据进入布隆过滤器根据散列函数散列后的下标便可以确认该数据是否存在。可以参考java中hashset判重与hascode()原理。
布隆过滤器误差:布隆过滤器不能完美的判断数据是否存在,举个例子说明:假设有个数组长度为8,值默认都是0,布隆过滤器放入2个数后,下标分别为0135、1246的值全变为了1,放入第3个数时,发现这个数经过多次散列函数后该标记的下标分别为0346,由于这些下标全部被标记为1布隆过滤器就会误以为该数已经存在不再更新下标值。


This is copyright.

...

...

00:00
00:00