Redis9 常见缓存问题

本文详细解析了缓存中的三大问题——缓存穿透、缓存击穿和缓存雪崩,以及它们的解决方案。缓存穿透可通过存储null值和使用布隆过滤器来避免;缓存击穿则可以通过设置Redis的setnx互斥锁来防止大并发操作数据库;缓存雪崩可通过设置不同过期时间和使用二级缓存来缓解。此外,探讨了缓存双写一致性问题,提出先更新数据库再删除缓存的策略,以减少数据不一致的可能性。
摘要由CSDN通过智能技术生成

背景

先查询缓存,缓存没有,再数据库
查完数据库,将查询结果放入缓存

缓存穿透

什么叫缓存穿透?

  • 某个时刻对于一些数据库中不存在的记录,疯狂的进行访问。
  • 一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如 DB)。如果key对应的value是一定不存在的,并且对该key并发请求量很大,就会对后端系统造成很大的压力。
  • 也就是说,对不存在的key进行高并发访问,导致数据库压力瞬间增大,这就叫做【缓存穿透】。

如何解决?

  1. 将null值也存入缓存,同时设置有效期。
  2. 布隆过滤器。主要用来判断该数据是否【不存在】。

缓存击穿

什么叫缓存击穿?

  • 针对热点数据,在某个时间点突然到期了,请求全部访问到数据库。 比如秒杀某一件商品。
  • 对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一种非常“热 点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题,这个和缓存雪崩的区别在于这里针对某一key缓存,前者则是很多key。
  • 缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存 过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

如何解决?

  • 使用redis的setnx互斥锁先进行判断,这样其他线程就处于等待状态,保证不会有大并发操作去操作数 据库。
	if(redis.sexnx()==1){
	 //先查询缓存 
	 //查询数据库 
	 //加入缓存 
	}

缓存雪崩

什么叫缓存雪崩?

  • 当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB) 带来很大压力。

如何解决?

  1. 在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程 查询数据和写缓存,其他线程等待。
  2. 不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
  3. 做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短 期,A2设置为长期(此点为补充)

缓存双写一致性

  • 一般来说,在读取缓存方面,我们都是先读取缓存,再读取数据库的。
  • 但是,在更新缓存方面,我们是需要先更新缓存,再更新数据库?还是先更新数据库,再更新缓存?还
    是说有其他的方案?

先更新数据库再更新缓存(不建议使用)

  • 操作步骤(线程A和线程B都对同一数据进行更新操作)
  1. 线程A更新了数据库
  2. 线程B更新了数据库
  3. 线程B更新了缓存
  4. 线程A更新了缓存
  • 问题1:脏读
  • 问题2:浪费性能

先更新数据库再删除缓存

  • 操作步骤(线程A更新、线程B读)

请求A进行写操作,删除缓存,此时A的写操作还没有执行完
请求B查询发现缓存不存在
请求B去数据库查询得到旧值
请求B将旧值写入缓存
请求A将新值写入数据库

  • 解决方案:延时双删策略,伪代码如下:
public** **void** write(**String** key, **Object** data){`` 
	db.updateData(data); 
	redis.delKey(key); 
	Thread.sleep(1000); 
	redis.deleKey(key); 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值