redis缓存击穿问题
需要缓存的业务考虑缓存的两种用法模式
1.读模式,如何读取一个数据,应该遵循先从缓存中读取,
如果缓存中没有,再在数据库读取,如果在数据库查到数据则再放到缓存中,并返回
2.写模式,如何保证缓存中的数据和数据库中的数据是一致的
可以使用双写模式或失效模式
- 双写模式:如果修改数据。如果缓存中有,则可以改完数据库中的数据后,再改缓存中的数据,把缓存中以前的数据覆盖掉
- 失效模式:改完数据库数据以后,可以把缓存中的数据直接清除掉,可以保证下一次从缓存中拿到的数据是最新的
高并发下的缓存穿透
指查询一个一定不存在的数据,由于缓存是不命中的,将会查询数据库,但是数据库也无此记录,我们没有将这次查询的null写入缓存,这将导致这个不存在的数据每次请求要到DB中去查询,失去了缓存的意义
风险:利用不存在的数据进行攻击,数据库瞬时压力增大,导致崩溃
解决:null结果写入缓存,并加入短暂的过期时间
高并发下的缓存失效问题-缓存雪崩
缓存雪崩是指在我们设置缓存时key采用了相同的过期时间,导致缓存在某一时间同时失效,请求全部转发到DB,DB瞬时压力过重雪崩
解决:原有的失效时间基础上加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间重复率就会降低,就很难引发群体失效的事件
高并发下的缓存失效问题-缓存击穿
对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发的访问,是一种非常热点的数据
如果这些key在大量请求同时进来前正好失效,那么所有对这个key的数据查询都落到db,对缓存造成击穿
解决:加速,大量并发只让一个去查,其他人等待,查询以后释放锁,其他人获取到锁,先查缓存,就会有数据,不用去db
问题1:
setnx占好了锁,业务代码异常或者程序执行过程中宕机,没有执行删除锁的逻辑,就会造成死锁
解决:设置锁的自动过期时间,即使没有删除,会自动删除
问题2:
setnx设置好,正要去设置过期时间,宕机,又死锁了
解决:设置过期时间和占位必须是原子性的,redis支持使用setnx ex命令
问题3:
删除锁直接删除?如果由于业务时间很长,锁自己过期了,我们直接删除,有可能把别人正在持有的锁删除了
结果:占锁的时候,指定锁的名称,每个人只能删除自己的锁
问题4:
如果正好判断是当前值,这个要删除锁的时候,锁已经过期,别人已经设置了新的值,那么我们删除的是别人的锁
解决:删除锁必须保证原子性,使用redis+lua脚本完成
总结:
无论是双写模式还是失效模式,都会导致缓存的不一致问题
1、缓存数据+过期时间足够解决大部分业务对于缓存的要求
2、如果是菜单,商品介绍等基础数据,也可以去使用canal订阅binlog的方式
3、通过加读写锁,写写的时候按顺序排好对,读读无所谓
我们能放入缓存的数据本就不应该是实时性、一致性要求超高的,所以缓存数据的时候加上过期时间,保证每天拿到当前最新的数据即可
我们不应该过度设计,增加系统的复杂性
遇到实时性,一致性要求高的数据,就应该查数据库,即使慢点
还没有评论,来说两句吧...