在实际项目开发中,我们都知道Redis不可能把所有的数据都缓存起来( 内存昂贵且有限 ),所以Redis需要对数据设置过期时间,并采用的是惰性删除+定期删除两种策略对过期键删除。
如果缓存数据 设置的过期时间是相同 的,并且Redis恰好将这部分数据全部删光了。这就会导致在这段时间内,这些缓存 同时失效 ,全部请求到数据库中。
这就是缓存雪崩 :
缓存雪崩如果发生了,很可能就把我们的数据库 搞垮 ,导致整个服务瘫痪,造成的后果很严重。
对缓存数据设置相同的过期时间,导致某段时间内缓存失效。”
对于“Redis挂掉了”,我们可以有以下的思路:
1. 缓存击穿
缓存击穿是指一个请求要访问的数据,缓存中没有,但数据库中有的情况。这种情况一般都是缓存过期了。
但是这时由于并发访问这个缓存的用户特别多,这是一个热点 key,这么多用户的请求同时过来,在缓存里面没有取到数据,所以又同时去访问数据库取数据,引起数据库流量激增,压力瞬间增大,直接崩溃给你看。
所以一个数据有缓存,每次请求都从缓存中快速的返回了数据,但是某个时间点缓存失效了,某个请求在缓存中没有请求到数据,这时候我们就说这个请求就"击穿"了缓存。
针对这个场景,对应的解决方案一般来说有三种。
借助Redis setNX命令设置一个标志位就行。设置成功的放行,设置失败的就轮询等待。就是在更新缓存时加把锁
后台开一个定时任务,专门主动更新过期数据
比如程序中设置 why 这个热点 key 的时候,同时设置了过期时间为 10 分钟,那后台程序在第 8 分钟的时候,会去数据库查询数据并重新放到缓存中,同时再次设置缓存为 10 分钟。
其实上面的后台续命思想的最终体现是也是永不过期。
只是后台续命的思想,会主动更新缓存,适用于缓存会变的场景。会出现缓存不一致的情况,取决于你的业务场景能接受多长时间的缓存不一致。
2. 缓存穿透
缓存穿透是指一个请求要访问的数据,缓存和数据库中都没有,而用户短时间、高密度的发起这样的请求,每次都打到数据库服务上,给数据库造成了压力。一般来说这样的请求属于恶意请求。
解决方案有两种:
就是在数据库即使没有查询到数据,我们也把这次请求当做 key 缓存起来,value 可以是 NULL。下次同样请求就会命中这个 NULL,缓存层就处理了这个请求,不会对数据库产生压力。这样实现起来简单,开发成本很低。
3. 缓存雪崩
缓存雪崩是指缓存中大多数的数据在同一时间到达过期时间,而查询数据量巨大,这时候,又是缓存中没有,数据库中有的情况了。
防止雪崩的方案简单来说就是错峰过期。
在设置 key 过期时间的时候,在加上一个短的随机过期时间,这样就能避免大量缓存在同一时间过期,引起的缓存雪崩。
如果发了雪崩,我们可以有服务降级、熔断、限流手段来拒绝一些请求,保证服务的正常。但是,这些对用户体验是有一定影响的。
4. Redis 高可用架构
Redis 高可用架构,大家基本上都能想到主从、哨兵、集群这三种模式。
哨兵模式:
它主要执行三种类型的任务:
哨兵其实也是一个分布式系统,我们可以运行多个哨兵。
然后这些哨兵之间需要相互通气,交流信息,通过投票来决定是否执行自动故障迁移,以及选择哪个从服务器作为新的主服务器。
哨兵之间采用的协议是 gossip,是一种去中心化的协议,达成的是最终一致性。
选举规则:
关于java清缓存前可以进后台方法,清完缓存不进了相关资料如下java我们在使用缓存时,往往先尝试去缓存中取值,如果没有,再去数据库取值,如果数据库也没有值,则根据业务需求,返回空或者抛异常。
如果用户一直访问一个数据库不存在的数据,比如id为-1的数据,就会导致每次请求都会先去缓存查一次,然后再去数据库查一次,造成严重的性能问题。这种情况就叫缓存穿透。
解决方案
以下几种解决方案:对请求参数做校验,比如用户鉴权校验,id做基础校验,id <= 0的直接拦截。
如果查询到数据库没有值,也将对应的key存进缓存中,value为null。这样下次查询就直接从缓存返回了。但这里的key的缓存时间应该比较短,比如30s。防止后面在数据库插入了这条数据,而用户获取不到。
使用布隆过滤器,判断一个key是否已经查过了,如果已经查过了,就不去数据库查询。
缓存击穿
缓存击穿指的是,一个key的访问量非常大,比如某秒杀活动,有1w/s的并发量。这个key在某一时刻过期,那这些大量的请求就会一瞬间到数据库,数据库可能会直接崩溃。
解决方案
缓存击穿的解决方案也有几种,可以配合使用:对于热点数据,慎重考虑过期时间,确保热点期间key不会过期,甚至有些可以设置永不过期。
使用互斥锁(比如Java的多线程锁机制),第一个线程访问key的时候就锁住,等查询数据库返回后,把值插入到缓存后再释放锁,这样后面的请求就可以直接取缓存里面的数据了。
缓存雪崩
缓存雪崩指的是,在某一时刻,多个key失效。这样就会有大量的请求从缓存中获取不到值,全部到数据库。还有另一种情况,就是缓存服务器宕机,也算做缓存雪崩。
解决方案
针对上述两种情况,缓存雪崩有两种解决方案:对每个key的过期时间设置一个随机值,而不是所有key都相同。
使用高可用的分布式缓存集群,确保缓存的高可用性,比如redis-cluster。
欢迎分享,转载请注明来源:夏雨云
评论列表(0条)