Redis学习笔记3


纸上得来终觉浅,深知此事要躬行。

使用redis不可避免会遇到的几个问题

1.缓存雪崩问题

什么是缓存雪崩

指的是当缓存服务器重启或者有大量的缓存在同一时间集体失效,导致请求直接打到数据库上,造成的数据库压力过大甚至崩溃,程序卡顿甚至崩溃。

可能产生缓存雪崩的场景

  • 流量激增:比如请求中的异常流量,用户重试次数过多导致系统负载压力过大或者是在大批量缓存失效的情况下涌入大量的请求。
  • 缓存刷新:假设Awei客户端,B为服务端,A所有的请求全都流向B系统,当请求数量或者并发量超出了B系统的承载能力时,就会造成B系统的崩溃。
  • 程序有bug:程序递归调用逻辑,资源位释放造成内存泄漏等问题。
  • 硬件故障:redis服务器宕机,机房断电,网络中断等。
  • 数据库问题:比如数据库的长事务。慢查询sql等。
  • 线程同步等待:系统间采用同步微服务调用模式,核心微服务和非核心微服务公用同一个线程池和消息队列,如果一个核心业务线程调用费核心业务线程,该费核心业务线程是由第三方系统完成的,当第三方系统本身出现问题,就会导致核心线程阻塞,一直处于等待状态,当等待超时之后,该条线程将会断掉,也有可能造成雪崩。

缓存雪崩的解决方案

  • 提高redis的高可用性,比如部署的时候采用哨兵模式或者redis集群模式;避免对大量的key设置相同的失效时间,尽量使失效时间分布均匀,比如可以在一定时间范围内随机设置失效时间。
  • 做多级缓存,比如可以用ehcache做一级缓存,redis做二级缓存;针对直接走数据库的请求进行限流和降级。
  • 开启redis持久化,当redis重启的时候可以快速恢复数据。
  • 设置热点数据不过期。

注:请求限流和服务降级属于系统整体解决方案,会在学习springcloud的时候记录下来。

2.缓存穿透问题

什么是缓存穿透

当用户的请求数据在缓存中查询不到,在数据库中也查询不到的时候,而且此时没有进行null值得有效处理,就可能会发生缓存穿透。

可能产生缓存穿透的场景

  • 黑客攻击:黑客恶意猜测查询key的命名方式,然后使用缓存中不存在的key值进行顿时间内大量查询请求。
  • 并发请求问题:第一次请求缓存的时候缓存中没有数据,但是在同一时间有大量相同的并发请求进入,那这时候如果没做处理,这些请求都会在同一时间查询数据库,导致缓存穿透。
  • 缓存和数据库都没有数据:当数据库中也没有对应的数据是,任何请求过来都会直接打到数据库,也可能会导致缓存穿透。

缓存穿透的解决方案

1.提前缓存热点数据,即在服务器启动的时候,就将可能频繁访问的数据缓存到数据库中。
2.针对缓存和数据库都不命中的数据,返回一个空对象并写入缓存中,然后设置一个较短的失效时间。该种方式会存在一个问题,当黑客恶意攻击时,可能会导致缓存中短时间内存在大量无用的key,占用redis大量的内存,降低了有效数据的命中率,严重的会导致redis崩溃。
3.采用布隆过滤器防止缓存穿透。布隆过滤器在文末介绍。

3.缓存击穿问题

什么是缓存击穿

指的是在缓存中存在一个key,在某一时间这个key失效了,与此同时,大量的并发请求又同事请求该key,那么缓存中查询不到,只能去数据库查询,大量请求打到数据库上,导致数据库压力剧增,这就是缓存击穿,说白了就是缓存中没有数据但是数据库中有数据,且同一时间大量请求涌入。

可能产生缓存击穿的场景

单个热点key失效,同时发生高并发查询数据库。

缓存击穿解决方案

1.针对同一时间请求缓存中不存在但是数据库存在的key时,程序中可以采用互斥锁机制,限制对数据库的请求,即第一个获得锁的可以请求数据库,请求完毕后将数据写入到缓存,其他的循环等待读取缓存。
2.设置热点数据永不过期,并定期更新热点数据。
3.采用布隆过滤器。
4.接口限流,服务熔断降级。

4.缓存与数据库双写一致性问题

为什么会产生一致性问题

产生不一致的原因主要在于并发读写访问,缓存和数据库相互交叉执行。
因为读和写是并发的,没办法保证顺序,如果删除了缓存,还没来得及写数据库,另一个线程就来读取了,发现缓存为空,则去数据库读取数据并写入缓存,此时存放到缓存中的新数据就是脏数据。如果先写库再删除缓存,在删除缓存之前,写库的线程当机了,没有删除掉缓存,则也会出现数据不一致的情况。如果redis是集群模式或者是主从模式,读写分离,由于redis复制存在一定的时间延迟,也有可能造成数据不一致。

解决方案

方案一:延时缓存双删策略
在写数据库的前后都进行缓存的删除操作,并且设定合理的超时时间
具体步骤为:
1.先删除缓存。
2.再更新数据库。
3.延时适当的时间。
4.再删除缓存。
伪代码如下:

public void writeDb(String key,Object data){
redis.delKey(key);
db.update(data);
Thread.sleep(500);
redis.delKey(key);
}

休眠时间选择
具体在写入数据库之后要休眠多长时间,需要根据自己的项目业务耗时以及redis主从同步耗时来确定,确保可以删除写数据库期间造成的缓存脏数据,此外还可以给缓存设置一个失效时间,这样可以达到数据最终一致性。
弊端(缺点)
会造成超时时间内的数据不一致;同时会增加写请求的耗时。
对该弊端的一个处理方式是在写请求的时候发送一个异步消息或者同步消息,把第二次的缓存删除交给消息中间件去处理,这样基本不会耽误写请求的时间。在消息消费者那边,收到消息后延迟一定的时间后再次删除缓存。

方案二:异步订阅淘汰策略
该方案仿照的是mysql的主从复制技术,利用mysql的binlog日志,异步订阅日志更新的内容,当日志中有更新时,通过分析,构造更新缓存的消息并发送到消息队列,然后消费者根据消息去更新缓存。

推荐一个讲解缓存与数据库一致性问题解决的网站。

5.redis缓存的并发竞争问题

简单来讲就是同一时间有多个redis线程去操作同一个key。

解决方案

1.乐观锁
采用redis自带的事务,用watch命令来实现。适用于所有的请求争抢同一个key,并且对修改顺序没有要求的场景。
注意:如果redis使用了数据分片,那么此方式不适用。
watch 命令会监视给定的每一个key,当 exec 时如果监视的任一个key自从调用watch后发生过变化,则整个事务会回滚,不执行任何动作。
2.分布式锁
在业务层面进行控制,操作redis缓存之前,现货区分布式锁,只有获得锁的客户端才能进行操作。
分布式锁的实现方式很多,redisson,zookeeper等。
如果需要顺序执行,则可以使用分布式锁+时间戳或者分布式锁+版本号的形式。
3.消息队列
如果并发量很大,可以通过消息队列的形式进行串行化处理。

布隆过滤器

什么是布隆过滤器

布隆过滤器(Bloom Filter)是1970年由布隆提出的,它实际上是由一个很长的二进制向量(位数组)和一系列随机的映射函数(哈希函数)组成的数据结构,布隆过滤器可以检索一个元素是否在一个集合中。
优点:

  1. 时间复杂度低,增加和查询元素的时间复杂度都为O(n),n为哈希函数的个数。
  2. 保密性强,布隆过滤器不保存元素本身。
  3. 存储空间小,使用位数组存储,占用内存空间比其他数据结构小很多。

缺点:
4. 存在一定的误判率,但是可以通过调整参数降低误判率比如增加位数组长度,增加随机映射函数的数量。
5. 不能获取元素本身。
6. 删除困难。

使用场景

  1. 解决Redis缓存穿透问题。
  2. 邮件过滤,比如邮件黑名单过滤。
  3. 爬虫网址过滤,过滤掉已经爬过得URL地址。
  4. 解决大数据场景下用户推荐数据的重复性问题。
  5. 判断数据库中的数据是否存在,减少磁盘IO操作。
    注:布隆过滤器可以判定一个元素肯定不存在,但是不能判定一个元素一定存在。

布隆过滤器原理(以Redis为例)

数据结构

Redis布隆过滤器底层使用的是一个大型位数组+多个无偏hash函数,初始化的时候位数组的值全部置为0。
无偏hash函数: 就是能把元素的hash值计算的比较均匀的hash函数,能使得计算后的元素下标比较均匀的映射到位数组中。
添加数据:

  1. 通过k个无偏hash函数计算得到k个hash值。
  2. 依次取模数组的长度,得到数组索引。
  3. 将计算得到的数组索引下标位置数据修改为1。

过滤数据:

  • 通过k个无偏hash函数计算得到k个hash值
  • 依次取模数组长度,得到数组索引
  • 判断索引处的值是否全部为1,如果全部为1则存在(这种存在可能是误判),如果存在一个0则必定不存在
尚硅谷是一个教育机构,他们提供了一份关于Redis学习笔记。根据提供的引用内容,我们可以了解到他们提到了一些关于Redis配置和使用的内容。 首先,在引用中提到了通过执行命令"vi /redis-6.2.6/redis.conf"来编辑Redis配置文件。这个命令可以让你进入只读模式来查询"daemonize"配置项的位置。 在引用中提到了Redis会根据键值计算出应该送往的插槽,并且如果不是该客户端对应服务器的插槽,Redis会报错并告知应该前往的Redis实例的地址和端口。 在引用中提到了通过修改Redis的配置文件来指定Redis的日志文件位置。可以使用命令"sudo vim /etc/redis.conf"来编辑Redis的配置文件,并且在文件中指定日志文件的位置。 通过这些引用内容,我们可以得出结论,尚硅谷的Redis学习笔记涵盖了关于Redis的配置和使用的内容,并提供了一些相关的命令和操作示例。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Redis学习笔记--尚硅谷](https://blog.csdn.net/HHCS231/article/details/123637379)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Redis学习笔记——尚硅谷](https://blog.csdn.net/qq_48092631/article/details/129662119)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值