上一篇文章《Redis缓存击穿的解决方案》我们介绍了缓存击穿的解决方案,这篇文章我们来介绍下缓存雪崩的解决方案。
什么是缓存雪崩
缓存雪崩指缓存中大量数据的失效时间集中在某一个时间段,导致在这个时间段内缓存失效并额外请求数据库查询数据的请求大量增加,从而对数据库造成极大的压力和负荷。
缓存雪崩的发生场景
缓存服务器宕机:当缓存服务器宕机或重启时,大量的访问请求将直接命中数据库,并在同一时间段内导致大量的数据库查询请求,从而将数据库压力大幅提高。 缓存数据同时失效:在某个特定时间点,缓存中大量数据的失效时间集中在一起,这些数据会在同一时间段失效,并且这些数据被高频访问,将导致大量的访问请求去查询数据库。 缓存中数据过期时间设计不合理:当缓存中的数据有效时间过短,且数据集中在同一时期失效时,就容易导致大量的请求直接查询数据库,加剧数据库压力。 波动式的访问过程:当数据的访问存在波动式特征时,例如输出某些活动物品或促销商品时,将会带来高频的查询请求访问,导致缓存大量失效并产生缓存雪崩。
缓存雪崩的解决方案
对于缓存雪崩的解决方案其实主要是多做几个缓存,例如我们同时把数据缓存到A实例,和缓存到B实例中去,一般我们在查询的时候主要首先查询实例A,实例A没有的情况下,我们再查询实例B,然后再查询数据库这样一个节奏进行解决。所以在做数据的时候我们会这么来操作
查询实例A,A如果有缓存,则直接返回 查询实例A,A没有查询到结果,然后去实例B里面查询,查询到了,把结果缓存到B里面去,同时给B设置一个随机的时间 查询实例A,A没有查询到结果,然后去实例B里面查询,实例B也没有查询到结果,然后去数据库查询,再把结果缓存到A实例和B实例中,同时给A实例和B实例设置不同的过期时间
对于这个缓存A实例和B实例的话,常见的做法有,使用redis缓存,使用ecache缓存等,主要是把数据存储到不同的地方去,但是在真实的业务中这里一般都采用redis多实例会好很多。
缓存雪崩的伪代码
/** * 测试缓存雪崩 */ private User getUserInfoById2(Long userId) { // 先从Ehcache缓存中获取 String userKey = "user_"+userId.toString(); User user = (User) redisTemplate.opsForValue().get(userKey); if(user == null){ // 再从Redis缓存中获取 user = (User) redisTemplate2.opsForValue().get(userKey); if(user != null){ redisTemplate.opsForValue().set(userKey, user, 300, TimeUnit.SECONDS); } } return user; }
以上就是完整的缓存雪崩的解决方案。
备注:
1、很多面试者对于缓存雪崩来说,大多都是看网上说的设置不同的随机时间来避免缓存雪崩,这个说的也对也不对,因为如果这么说的话,一般我们会认为这个人只是看了网上的文章而没有实际的工作经验,因为面对百万级流量的时候,相同业务的缓存时间会有个大致时间,例如5分钟,这样子即使加上缓存随机时间的话,一般也就在5分钟过10秒以内,这样子由于流程非常大,缓存肯定是很多的,这也会带来大量的缓存失效问题,然后给数据库带来压力,因此这里我们还是要有主备的思维。才能根除掉缓存雪崩带来的问题。
最后,按照惯例,附上本案例的源码,登录后即可下载。
还没有评论,来说两句吧...