cache中的key mutex问题解决及延伸应用

            [文章作者:孙立 链接:http://www.cnblogs.com/sunli/ 更新时间:2010-07-27]

         上周六去参加了csdn举办的TUP活动,最后一场的Tim Yang讲的《微博cache设计谈》,个人觉得讲得非常好和非常到位,其中有两点非常感同身受,就是内网流量问题和cache的key mutex问题导致大量请求穿透到db。后他又写了一篇博客《Memcache mutex设计模式》阐述这个问题。关于cache的key mutex问题在我的开发中叶碰到过很多,这里也就谈下我的解决办法。问题的产生如下图:

    2010090709352598.jpg

                                         图一:key mutex问题

         我这里指的cache不局限于memcached,事实上,key mutex在很多场合都是需要的,比如mysql中的innodb中说的机遇记录集的锁也可以当成key mutex。

      http反向代理服务器cache的key mutex问题

         我在09年为一个当时性能不是很高,但是短时间又难于优化的一个系统开发了一个反向代理服务器ICProxy(类似于squid,varnish等,只是增加了一些自己的业务逻辑)来提高系统的性能。但是很快问题就来了,

在访问高峰期,比如

  • 一个热门的新闻页面,设置缓存5分钟
  • 5分钟后,会有大量的请求在同一时间得到缓存失效的标识
  • 大量请求并同时都穿透到后端web服务器请求加载数据到缓存,造成后端频繁宕机
这就是所说的key mutex问题,没有对统一资源的请求加锁来限制穿透访问,由于ICProxy是java开发的,可以很方便的使用锁来进行控制。这里就不贴源代码了,我相信你一定知道怎么实现。
       Memcached的key mutex问题
     memcached的key mutex问题在Tim Yang的博客《Memcache mutex设计模式》已经把产生的场景说得很清楚,也提到了两种解决办法。问题的解决如下图:
 
2010090709371444.jpg
 
     在以前的系统,我们也碰到过这个问题,因此我开发了一个phplock项目,因为我们在前段主要使用php,所以这里我再为php增加一种方法
     方法三:
    
ContractedBlock.gif ExpandedBlockStart.gif 代码<?php
 
    
// 获取memcached实例
$cache = IFengMem :: getInstance ( ' bbsmemcache ' );
// 获取缓存中的数据
$result = $cache -> get ( $cacheKey );
if ( $result === false ) {
require_once ' class/class.phplock.php ' ;
// 初始化锁,$cacheKey必须传入,用于内部的hash
$lock = new PHPLock ( ' locks/ ' , $cacheKey );
$lock -> startLock ();
// 加锁
$lock -> Lock ();
// 进入锁后,查询一次缓存看是否已经有数据了
$result = $cache -> get ( $cacheKey );
// 如果还是没有数据,表示是自己最先进去到锁的,查询数据库并加载到缓存
if ( $result === false ) {
$query = $db -> query ( $sql );
$result = $db -> fetchArray ( $query );
$cache -> set ( $cacheKey , $result , $cacheTime );
}
// 释放锁
$lock -> unlock ();
$lock -> endLock ();
}
?>

        phplock你可以在 http://code.google.com/p/phplock/获取到。

        在php应用中,特别是基于nginx等fast-cgi的应用,你应该尽量优化你的查询,让其尽量的快,缩短锁等待,不然不管是穿透到后端db还是在锁等待,都会导致系统负载的急剧上升。你因该根据你系统的业务情况,看是否可以后台线程来更新缓存。

      注意

      在以上的场景中,锁的利用实际上是使用了分离锁,也即是把大量需要进行锁的资源hash到指定的数目锁上,避免过多的锁,也即不是直接进行全局的lock(),这样会降低系统的吞吐量,在phplock中,有个$hashNum可以设置可以hash桶数目,也即可以同时进行访问的key的数量,这样也避免了大量的不同的key的穿透到数据库,phplock是单机版本的,对于多台机器使用的话,可能会有最大机器数的请求穿透的服务器,如果你的web服务器不是非常多的话,也不会有什么问题。

    key mutex的延伸应用

     在很多系统中,我们要对某一个资源进行一个比较耗时的操作时,比如图片下载,网络请求,数据查询,搜索等,由于在大并发下,有大量的请求到同一个资源和不同的资源,那么key mutex的场景都是适用的。当你要开发一个nosql数据库的时候,你必须要考虑这个问题。

     比如你要开发一个类似于memcached的increment的数据累加器,

     你可能不希望

 

 
  
lock.lock();
int num = storage.get(key);
storage.set(key,num
+ 1 );
lock.unlock();

 

而是如下的方式来提高吞吐量

 

 
  
lock.lock(key);
int num = storage.get(key);
storage.set(key,num
+ 1 );
lock.unlock(key);

 

这个比较类似于mysql中的mysiam和innodb的表锁和行锁的概念,显然行锁的并发能力比表锁高很多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值