注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

小葫芦君(汉斯的博客)

博客迁移到新博客:https://blog.ssxingshou.com

 
 
 

日志

 
 
关于我

小小葫芦商城,为您提供高品质的商品,一流的产品,一流的包装服务,一流的物流服务,放心购买

网易考拉推荐

应对Memcached缓存失效,导致高并发查询DB的四种思路  

2014-04-10 10:40:12|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
 转自一位同事的文章:

当Memcached缓存失效时,容易出现高并发的查询DB,导致DB压力骤然上升。

这篇blog主要是探讨如何在缓存将要失效时,及时地更新缓存,而不是如何在缓存失效之后,如何防止高并发的DB查询。

解决这个问题有四种思路:

比如一个key是aaa,失效时间是30s。


1.定期从DB里查询数据,再刷到memcached里

这种方法有个缺点是,有些业务的key可能是变化的,不确定的。

而且不好界定哪些数据是应该查询出来放到缓存中的,难以区分冷热数据。


2.当缓存取到为null时,加锁去查询DB,只允许一个线程去查询DB

这种方式不太靠谱,不多讨论。而且如果是多个web服务器的话,还是有可能有并发的操作。


3.在向memcached写入value时,同时写入当前机器在时间作为过期时间

当get得到数据时,如果当前时间 - 过期时间 > 5s,则后台启动一个任务去查询DB,更新缓存。

当然,这里的后台任务必须保证同一个key,只有一个线程在执行查询DB的任务,不然这个还是高并发查询DB。

缺点是要把过期时间和value合在一起序列化,取出数据后,还要反序列化。很不方便。


网上大部分文章提到的都是前面两种方式,有少数文章提到第3种方式。下面提出一种基于两个key的方法:

4.两个key,一个key用来存放数据,另一个用来标记失效时间

比如key是aaa,设置失效时间为30s,则另一个key为expire_aaa,失效时间为25s。

在取数据时,用multiget,同时取出aaa和expire_aaa,如果expire_aaa的value == null,则后台启动一个任务去查询DB,更新缓存。和上面类似。


对于后台启动一个任务去查询DB,更新缓存,要保证一个key只有一个线程在执行,这个如何实现?

对于同一个进程,简单加锁即可。拿到锁的就去更新DB,没拿到锁的直接返回。


对于集群式的部署的,如何实现只允许一个任务执行?

这里就要用到memcached的add命令了。

add命令是如果不存在key,则设置成功,返回true,如果已存在key,则不存储,返回false。

当get expired_aaa是null时,则add expired_aaa 过期时间由自己灵活处理。比如设置为3秒。

如果成功了,再去查询DB,查到数据后,再set expired_aaa为25秒。set aaa 为30秒。

综上所述,来梳理下流程:

比如一个key是aaa,失效时间是30s。查询DB在1s内。

  • put数据时,设置aaa过期时间30s,设置expire_aaa过期时间25s;
  • get数据时,multiget  aaa 和 expire_aaa,如果expired_aaa对应的value != null,则直接返回aaa对应的数据给用户。如果expire_aaa返回value == null,则后台启动一个任务,尝试add expire_aaa,并设置超时过间为3s。这里设置为3s是为了防止后台任务失败或者阻塞,如果这个任务执行失败,那么3秒后,如果有另外的用户访问,那么可以再次尝试查询DB。如果add执行成功,则查询DB,再更新aaa的缓存,并设置expire_aaa的超时时间为25s。

总结:

我个人是倾向于第4种方式的,因为很简单,直观。

这种两个key的方式,还有一个好处,就是数据是自然冷热适应的。如果是冷数据,30秒都没有人访问,那么数据会过期。

如果是热门数据,一直有大流量访问,那么数据就是一直热的,而且数据一直不会过期。

  评论这张
 
阅读(548)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017