缓存热点key问题(mutex key)

本文探讨了缓存热点key引发的问题,即在缓存失效瞬间大量线程构建缓存导致后端负载过大。文章提出了四种解决方案:1) 使用互斥锁(mutex key);2) 提前使用互斥锁;3) "永远不过期"策略;4) 资源保护。每种方案都有其适用场景,选择时需结合业务需求。
摘要由CSDN通过智能技术生成

一、引出热点key问题

 

       我们通常使用 缓存 + 过期时间的策略来帮助我们加速接口的访问速度,减少了后端负载,同时保证功能的更新,一般情况下这种模式已经基本满足要求了。

       但是有两个问题如果同时出现,可能就会对系统造成致命的危害:

      (1) 这个key是一个热点key(例如一个重要的新闻,一个热门的八卦新闻等等),所以这种key访问量可能非常大。

      (2) 缓存的构建是需要一定时间的。(可能是一个复杂计算,例如复杂的sql、多次IO、多个依赖(各种接口)等等

 

       于是就会出现一个致命问题:在缓存失效的瞬间,有大量线程来构建缓存(见下图),造成后端负载加大,甚至可能会让系统崩溃 。

 

    

         

 

 

二、四种解决方案

 

我们的目标是:尽量少的线程构建缓存(甚至是一个) + 数据一致性 + 较少的潜在危险,下面会介绍四种方法来解决这个问题:

 下载  

1. 使用互斥锁(mutex key): 这种解决方案思路比较简单,就是只让一个线程构建缓存,其他线程等待构建缓存的线程执行完,重新从缓存获取数据就可以了(如下图)

     如果是单机,可以用synchronized或者lock来处理,如果是分布式环境可以用分布式锁就可以了(分布式锁,可以用memcache的add, redis的setnx, zookeeper的添加节点操作)。

     下面是Tim yang博客的代码,是memcache的伪代码实现下载  

      

Java代码   
  1. if (memcache.get(key) == null) {  
  2.     // 3 min timeout to avoid mutex holder crash  
  3.     if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {  
  4.         value = db.get(key);  
  5.         memcache.set(key, value);  
  6.         memcache.delete(key_mutex);  
  7.     } else {  
  8.         sleep(50);  
  9.         retry();  
  10.     }  
  11. }  
     

 

      如果换成redis,就是:下载  

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值