首页 > 技术文章 > 【分布式】分布式缓存

clarino 2020-07-11 00:08 原文

缓存淘汰算法

  1. FIFO:先进先出,在这种淘汰算法中,先进入缓存的会先被淘汰,会导致命中率很低。
  2. LRU:最近最少使用算法,每次访问数据都会将其放在我们的队尾,如果需要淘汰数据,就只需要淘汰队首即可。仍然有个问题,如果有个数据在 1 分钟访问了 1000次,再后 1 分钟没有访问这个数据,但是有其他的数据访问,就导致了我们这个热点数据被淘汰。
  3. LFU:最近最少频率使用,利用额外的空间记录每个数据的使用频率,然后选出频率最低进行淘汰。这样就避免了 LRU 不能处理时间段的问题。

上面三种策略各有利弊,实现的成本也是一个比一个高,同时命中率也是一个比一个好。Guava Cache虽然有这么多的功能,但是本质上还是对LRU的封装,如果有更优良的算法,并且也能提供这么多功能,相比之下就相形见绌了。

LFU的局限性 :在 LFU 中只要数据访问模式的概率分布随时间保持不变时,其命中率就能变得非常高。比如有部新剧出来了,我们使用 LFU 给他缓存下来,这部新剧在这几天大概访问了几亿次,这个访问频率也在我们的 LFU 中记录了几亿次。但是新剧总会过气的,比如一个月之后这个新剧的前几集其实已经过气了,但是他的访问量的确是太高了,其他的电视剧根本无法淘汰这个新剧,所以在这种模式下是有局限性。

LRU的优点和局限性 :LRU可以很好的应对突发流量的情况,因为他不需要累计数据频率。但LRU通过历史数据来预测未来是局限的,它会认为最后到来的数据是最可能被再次访问的,从而给与它最高的优先级。

 

缓存问题隐患 

  • 缓存无底洞
  • 缓存穿透
  • 缓存雪崩
  • 缓存失效
  • 热点key倾斜
  • 热点key重建
  • 缓存数据库双写不一致

 

1、缓存雪崩

  问题现象:大量的缓存同一时刻失效;

  典型问题:所有首页的Key失效时间都是12小时,秒杀活动大量用户涌入,假设当时每秒 6000 个请求,本来缓存在可以扛住每秒 5000 个请求,但是缓存当时所有的Key都失效了。此时 1 秒 6000 个请求全部落数据库。

  解决方案:

    把每个Key的失效时间都加个随机值,这样可以保证数据不会在同一时间大面积失效

    setRedis(Key,value,time + Math.random() * 10000);

    如果Redis是集群部署,将热点数据均匀分布在不同的Redis库中也能避免全部失效的问题;

    或者设置热点数据永远不过期,有更新操作就更新缓存就好了(比如运维更新了首页商品,那你刷下缓存就完事了,不要设置过期时间)

2、缓存穿透

  问题现象:缓存和数据库中都没有的数据,而用户不断发起请求,我们数据库的 id 都是1开始自增上去的,如发起为id值为 -1 的数据或 id 为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大,严重会击垮数据库。

  解决方案:

    接口层增加校验,比如用户鉴权校验,参数做校验,不合法的参数直接代码Return,比如:id 做基础校验,id <=0的直接拦截等。

         将对应Key的Value对写为null,过期时间设置很短

    高级用法布隆过滤器(Bloom Filter)这个也能很好的防止缓存穿透的发生,他的原理也很简单就是利用高效的数据结构和算法快速判断出你这个Key是否在数据库中存在,不存在你return就好了,存在你就去查了DB刷新KV再return。

         利用nginx对单个IP的访问频次做阈值控制

3、缓存击穿

  指一个Key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个Key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库。

  解决方案:

    设置热点数据永远不过期。或者加上互斥锁就能搞定了

   一般避免以上情况发生我们从三个时间段去分析下:

    • 事前:Redis 高可用,主从+哨兵,Redis cluster,避免全盘崩溃。

    • 事中:本地 ehcache 缓存 + Hystrix 限流+降级,避免MySQL被打死。

    • 事后:Redis 持久化 RDB+AOF,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。

4、数据库与缓存双写不一致问题(秒杀场景)

  读多写少: 引入分布式锁的读写锁如Redisson.getReadWriteLock(lockKey)

 


 

真正支撑高并发及高可用的复杂系统中缓存架构?   

节选自:   【中华石杉】亿级流量电商详情页系统的大型高并发与高可用缓存架构实战  P1

如何让redis集群支撑几十万QPS高并发+99.99%高可用+TB级海量数据+企业级数据备份与恢复?: Redis企业级集群架构
如何支撑高性能及高并发到极致?同时缓存架构最终的安全保护层?:(nginx+luna)+redis+ehcache三级缓存架构
如何解决大value缓存的全量更新效率低下问题?:缓存维度化拆分解决方案
如何将缓存命令率提升到极致?: 双层nginx部署架构,一致性hash流量分发策略
如何解决高并发场景下,如何解决数据库与缓存双写时树不一致情况?:数据库+缓存双写一致性解决方案
如何解决高并发场景下,缓存重建时的分布式并发冲突问题?:基于zookeeper分布式锁的缓存并发重建解决方案
如何解决高并发场景下,缓存冷启动Mysql瞬间被打死问题?:基于storm实时统计热数据的分布式快速缓存预热解决方案
如何解决高并发场景下,缓存雪崩问题?事前+事中+事后的三层解决方案
如何解决高并发场景下,缓存穿透问题?避免Mysql带来过大压力:缓存穿透解决方案
如何解决高并发场景下,缓存失效问题?避免给redis集群带来过大压力?: 缓存失效解决方案
如何解决热点缓存导致单机负荷瞬间超高?:基于storm的实时热点发现,及毫秒级实时热点缓存负载均衡降级

推荐阅读