Memcache mutex设计模式[高并发解决方案]

来源:互联网 发布:ipad4安装不了软件 编辑:程序博客网 时间:2024/06/05 14:40

场景

Mutex主要用于有大量并发访问并存在cache过期的场合,如

  • 首页top 10, 由数据库加载到memcache缓存n分钟
  • 微博中名人的content cache, 一旦不存在会大量请求不能命中并加载数据库
  • 需要执行多个IO操作生成的数据存在cache中, 比如查询db多次

问题

在大并发的场合,当cache失效时,大量并发同时取不到cache,会同一瞬间去访问db并回设cache,可能会给系统带来潜在的超负荷风险。我们曾经在线上系统出现过类似故障

解决方法 

方法一

高并发时,增加data_lock信号标识,只充许一个用户update cache,在cache数据期间,其它并发用户等待,只到这个用户cache成功,当然这个地方需要设置最大等待时间,毕竟当很长时间cache不成功时,不能让用户一直等待:

function get_my_data2() {        $cache_id = "mykey";        $data = $memcache_obj->get($cache_id);        if ( !$data ) {            // check to see if someone has already set the lock            $data_lock = $memcache_obj->get($cache_id . ‘_qry_lock’);            if ( $data_lock ) {                $lock_counter = 0;                // loop until you find that the lock has been released.  that implies that the query has finished                do while ( $data_lock ) {                    // you may only want to wait for a specified period of time.                    // one second is usually sufficient since your goal is to always have sub-second response time                    // if you query takes more than 1 second, you should consider "warming" your cached data via a cron job                    if ( $lock_counter > $max_time_to_wait ) {                        $lock_failed = true;                        break;                    }                    // you really want this to be a fraction of a second so the user waits as little as possible                    // for the simplicity of example, I’m using the sleep function.                    sleep(1);                    $data_lock = $memcache_obj->get($cache_id . ‘_qry_lock’);                }                // if the loop is completed, that either means the user waited for too long                // or that the lock has been removed.  try to get the cached data again; it should exist now                $data = $memcache_obj->get($cache_id);                if ( $data ) {                    return $data;                }            }            // set a lock for 2 seconds            $memcache_obj->set($cache_id . ‘_qry_lock’, true, 2);            $data = get_data_from_db_function();            $memcache_obj->set($cache_id, $data, $sec_to_cache_for);            // don’t forget to remove the lock            $memcache_obj->delete($cache_id . ‘_qry_lock’);        }        return $data;    }

方法二 

需要给数据增加一个cache过期时间标识,高并发时,在用户取数据时,检查cache是否快要过期,如果即将过期,则充许一个用户去更新cache,其它用户依然访问没有update的数据。


function get_my_data3() {        $cache_id = "mykey";        $data = $memcache_obj->get($cache_id);        // if there is cached data and the expire timestamp has already expired or is within the next 2 minutes        // then we want the user to freshen up the cached data        if ( $data && ($data[‘cache_expires_timestamp’] – time()) < 120 ) {            // if the semaphore lock has already been set, just return the data like you normally would.            if ( $memcache_obj->get($cache_id . ‘_expire_lock’) ) {                return $data;            }            // now we want to set the lock and have the user freshen the data.            $memcache_obj->set($cache_id . ‘_expire_lock’, true, 2);            // by unsetting the data it will cause the data gather logic below to execute.            unset($data);        }        if ( !$data ) {            // be sure to include all of the semaphore logic from example 2            // set the _qry_lock for 2 seconds            $memcache_obj->set($cache_id . ‘_qry_lock’, true, 2);            $raw_data = get_data_from_db_function();            $data[‘cache_expires_timestamp’] = time() + $sec_to_cache_for;            $data[‘cached_data’] = $raw_data;            $memcache_obj->set($cache_id, $data, $sec_to_cache_for);            // remove the _qry_lock            $memcache_obj->delete($cache_id . ‘_qry_lock’);            // remove the _expires_lock            $memcache_obj->delete($cache_id . ‘_expires_lock’);        }        return $data;    }

更多资料:

Memcached FAQ中也有详细介绍 How to prevent clobbering updates, stampeding requests
http://www.grepmymind.com/2008/01/11/memcached-php-semaphore-cache-expiration-handling/

原创粉丝点击