1 redis雪崩的解决方案
什么是缓存雪崩?
(1)Redis挂掉了,请求全部走数据库。
(2)对缓存数据设置相同的过期时间,导致某段时间内缓存失效,请求全部走数据库。
1.1 针对redis数据过期失效的策略
在缓存过期的短时间内存在数据库短暂压力问题,为解决该问题,可采用以下两种解决方案:
第一种:在缓存的时候给过期时间加上一个随机值,这样就会大幅度的减少缓存在同一时间过期。
第二种:我们以两个键值对的缓存代替之前的一个,将缓存时间(key-time),和缓存数据(key-data)分离,这样当缓存过期时,第一个线程发现key-time没有,则先更新key-time,然后去查询数据库(或任何比较耗时的数据查询方式),并更新key-data的值,当后续线程来获取数据时,虽然第一个还没有从数据库查完并更新缓存,但发现key-time存在,会获取旧的数据。
虽然按这种方式获取的数据中c类型的数据为旧数据,但可以做到:在缓存过期时不至于在短时间内对数据库造成较高压力,在数据库不可用,同时缓存过期的时候,其调用服务皆不可用,造成连锁反应,而已该解决方式,则可以返回过期数据,为修复数据库赢得宝贵时间(缓解雪崩效应)
1.2 针对“Redis挂掉了,请求全部走数据库”这种情况
我们可以有以下的思路:
事发前:实现redis的高可用,尽量避免redis挂掉这种情况的发生。
事发中:万一redis真的挂了,可以设置本地缓存+限流,尽量避免数据库被干掉,确保服务正常工作。
事发后:redis持久化,重启后能够快速恢复缓存数据。
2 缓存穿透的解决方案
什么是缓存穿透?就是请求的数据在缓存大量不命中,导致请求走数据库。而缓存穿透如果发生了,也可能把我们的数据库搞垮,导致整个服务瘫痪!
解决缓存穿透也有两种方案:
(1)提前进行拦截过滤:由于请求的参数是不合法的(每次都请求不存在的参数),于是我们可以使用布隆过滤器(BloomFilter)或者压缩filter提前拦截,不合法就不让这个请求到数据库层!
(2)设置空对象:当我们从数据库找不到的时候,我们也将这个空对象设置到缓存里边去。下次再请求的时候,就可以从缓存里边获取了。这种情况我们一般会将空对象设置一个较短的过期时间。
3 缓存和数据库双写一致性问题
主要就是两种策略:第一种:先删除缓存,再更新数据库;第二种:先更新数据库,再删除缓存。
第一种策略在并发的情况,也会出现不一致的情况,弥补策略,采用延时双删策略。如果第二次删又失败的话,又考虑性能的话,可采用异步重试的方式进行。
同样,针对第二种策略,在并发的情况下,也会出现数据不一致的情况,同样可以采取延迟双删的策略。如果第二次删又失败的话,又考虑性能的话,可采用异步重试的方式进行。
针对二删和重试操作,对业务代码会造成比较多的侵入,针对这种情况,可以启动一个订阅程序去订阅数据库的binlog,获得需要操作的数据。在应用程序中,另起一段程序,获得这个订阅程序传来的信息,进行删除缓存操作。