Redis常见场景问题和解决方案

缓存穿透(查不到数据)

概述

当用户想要查询一个数据,发现Redis中不存在,也就是所谓的缓存没有命中,于是这个数据请求就会打到数据库中。结果数据库中也不存在这条数据,那么结果就是什么都没查询出来。那么当用户很多时候的查询,缓存中都没有数据,请求直接打到数据库中,这样就会给数据库造成很大的压力,缓存的作用也就几近于失效了,那么这种情况就叫做缓存穿透。

解决方案

方案一:保存空值

当数据库中也查询不到数据时,那么将返回的空对象也缓存起来,同时设置一个过期时间,之后再访问这个数据将会从缓存中获取,从而起到保护数据库的作用。

例如:查询userId=100的用户信息(key=[userId],value=[用户json]),那么如果缓存和DB中都不存在,则在缓存中保存一条key=100,value=""的数据,那么用户再查询userId=100的时候,就直接可以返回空了。不需要查询DB。

方案二:布隆过滤器

步骤1:将数据库所有的数据加载到布隆过滤器。

步骤2:当有请求来的时候先去布隆过滤器查询,判断查询的数据是否存在。

步骤3:如果Bloom Filter判断数据不存在,那么直接返回空给客户端。

步骤4:如果Bloom Filter判断数据存在,那么则查询缓存DB

步骤5:将DB中查询的结果返回给客户端(并且缓存到Redis中)

缓存击穿(高并发查询某数据,且缓存过期)

概述

指一个非常热点的key,在不停的高并发请求着,那么当这个key在缓存中失效的一瞬间,持续对这个key的高并发就击穿了缓存,直接请求到了数据库,就像在一个屏障上早开了一个洞

当热点key过期失效的一瞬间,高并发突然融入,会对数据库突然造成巨大的压力,严重的情况甚至会造成数据库宕机。

解决方案

方案一:设置热点数据永不过期

从缓存层面来看,没有设置过期时间,所以不会出现热点key过期后所产生的缓存击穿问题。

方案二:加互斥锁

使用分布式锁,当缓存数据过期后,保证对每个热点key同时只有一个线程去查询后端服务,并将热点数据添加到缓存。

缓存雪崩(缓存大批量失效或Redis宕机)

概述

指在某一个时间段,缓存集中过期失效,或Redis宕机,导致针对这批数据的查询都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。

其实缓存集中过期,倒不是最致命的,比较致命的是Redis发生节点宕机或断网。因为缓存集中过期后,数据库压力增大,但是随着缓存的创建,压力也会逐渐变小。但是Redis服务节点宕机,对数据库服务器造成的压力是不可预知的,很有可能是持续压力而最终造成数据库宕机。

解决方案

方案一:配置Redis集群

通过配置Redis集群,提升高可用性,那么即使挂掉几个Redis节点,集群内的其他Redis节点依然可以继续对外提供服务。

方案二:限流降级

缓存失效后,通过加锁队列来控制读取数据库且写入缓存的线程数量。

方案三:数据预热分散过期时间

在正式部署之前,先把可能被高频访问的数据预先访问一遍,这样大部分热点数据就加载到缓存中了,并且通过设置不同的过期时间,让缓存失效的时间尽量均匀,防止同一时刻大批量缓存失效。

布隆过滤器

概念介绍

布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率删除困难

布隆过滤器的特征是:它可以判断某个数据一定不存在,但是无法判断一定存在。(确实有点拗口,但当我们介绍完它的原理,就很容易明白了)

使用场景

场景一:原本有10亿个号码,现在又来了10万个号码,如何快速判断这10万个号码是否在10亿个号码库中?

场景二:需要爬虫的网站千千万万,对于一个新的网站url,我们如何判断这个url我们是否已经爬过了?

解决方案

针对上面的需求,我们一般会想到两种解决方案:

方案一:将10亿个号码存入数据库中,进行数据库查询,准确性有了,但是速度会比较慢。

方案二:将10亿号码放入内存中,比如Redis缓存中,这里我们算一下占用内存大小:10亿*8字节=8GB,通过内存查询,准确性和速度都有了,但是大约8GB的内存空间,挺浪费内存空间的。

那么对于类似这种,海量数据集合,如何准确快速的判断某个数据是否在大数据量集合中,并且不占用内存?那么布隆过滤器应运而生了。

实现原理

布隆过滤器是什么?

它是一种数据结构,是由一串很长的二进制向量组成,也可以将其看成一个二进制数组。既然是二进制,那么里面存放的不是0,就是1,但是初始默认值都是0。如下图所示:

添加数据如何处理?

当要插入一个元素时,将其数据分别输入k个哈希函数,产生k个哈希值。以哈希值作为位数组中的下标,将所有k个对应的比特置为1

比如,下图hash1(x)=1,那么在第2个格子将0变为1(数组是从0开始计数的),hash2(x)=6,那么将第5个格子置为1hash3(x)=16,那么将第16个格子置位1,依次类推。如下图所示(只演示hash1~hash3):

如何判断数据是否存在?

知道了如何向布隆过滤器中添加一个数据,那么新来一个数据,我们如何判断其是否存在于这个布隆过滤器中呢?

很简单,我们只需要将这个新的数据通过上面自定义的几个哈希函数,分别算出各个值,然后看其对应的地方是否都是1,如果存在一个不是1的情况,那么我们可以说,该新数据一定不存在于这个布隆过滤器中

那么反过来说,如果通过哈希函数算出来的值,对应的地方都是1,那么我们能够肯定的得出:这个数据一定存在于这个布隆过滤器中吗?

答案是否定的,因为多个不同的数据通过hash函数算出来的结果是会有重复的,所以会存在某个位置是别的数据通过hash函数置为的1。即:“假阳性”(false positive)如下图所示:

今天的文章内容就这些了:

写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享 。

更多技术干货,欢迎大家关注公众号“爪哇缪斯” ~ \(^o^)/ ~ 「干货分享,每天更新」

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值