关于缓存的几个问题

  这里的缓存是指各个缓存框架,比如现在比较火的redis、memcached,以及有些过气的ehcache、oscache等。缓存作为挡在数据库前面的屏障,减少DB的调用次数,起到了绿化带似的缓冲和隔离作用。又因为缓存的存储特性能起到快速存取、提高响应速度的作用。这里不谈缓存的好处,只聊缓存的几点麻烦。

  一、缓存并发。适用场景:某缓存KEY在短时间内被大量查询,刚好发生在缓存KEY刚好到达过期时间的那一刻,或者DB刚好更新数据通知缓存也做了更新的那一刻。在这个时间点,缓存是没有数据的,那么自然要到DB来查了,并发带来的查询压力顺势传递给DB。

应对措施:针对缓存查询加锁,只放第一个查询直达DB,其他查询锁在外面。当第一个查到数据后把锁解开,其他查询这时从缓存就能查到数据了。

  二、缓存穿透。适用场景:某缓存KEY没被命中,DB也没数据。因为DB永无数据,缓存永远无法命中,请求每次都将直达DB。形象的说就是穿透,或者击穿。少量这种请求的话关系不大,如果是大量、并发的话,DB脆的当场就跪了。

  应对措施1:返回空值时也缓存起来,下次查询请求还来,缓存就说是空值打发了,把DB保护起来。对并发、重复刷是顶住了,但如果量大的话,要耗内存,可能会挤掉其他正常的数据,需要设置一个较短的过期时间,用完就扔。

  应对措施2:把这种值不存在的key都收集到一个集合中,后续请求若在集合中则直接过滤。如果量大的话,维护该这个黑名单也是个麻烦事,而且每次请求都来黑名单点一次名也是件费力的事。

  三、缓存雪崩。适用场景:缓存启动、重启或失效时间设置不均衡,导致大量缓存同一时间失效。假设所有缓存同时失效,那么这一刻缓存就对DB失去了意义,DB只能裸奔了。当然后面数据还会慢慢重新加载到缓存,DB边裸奔边穿衣,前提是能扛得住。

  应对措施1:针对启动、重启的情况规划缓存预热。针对缓存KEY约好一起失效的情况,从设置失效时间入手,不能让它们约,给不同的KEY设置失效时间。简单点设置随机时间,业务有规划的按不同KEY进行规划。

  应对措施2:问题既然是缓存失效引起的,那么就不要失效了。一层永久、全量缓存,一层本地缓存,搞二级缓存。麻烦是加机器、重搭缓存框架,伤筋动骨。

原文地址:https://www.cnblogs.com/wuxun1997/p/7758246.html