一个memcache可以同时由两个不同的进程更新吗?

时间:2012-05-21 07:30:24

标签: memcached

我正在使用CakePHP的memcache。

我正在运行一个更新memcache密钥的多线程进程。

因此,两个不同进程最终更新同一个memcache密钥的概率为10%,这会引发错误。

1 个答案:

答案 0 :(得分:0)

你可以锁定"使用以下代码进行设置之前的密钥。

此代码假定您拥有Instrumentation-for-php库:

http://code.google.com/p/instrumentation-for-php

如果您不想使用它,请注释掉仪表线

function acquire_mutex_or_wait($key,$memcache = false) {
    Instrumentation::get_instance()->increment('memcache_mutex_requests', 1);
    if($memcache === false) {
            #bring in memcache from global scope
            global $memcache;
    }
    #prepend LOCK:: to the key to designate the new key as a lock for the given key
    $key = "LOCK::$key";

    #generate a random number for the lock (see below)
    $lockval = mt_rand(1,2^31);

    #add is SUPPOSED to be atomic, but it isn't really with multiple servers
    #to protect against two connections getting the mutex we initialize it
    #to a random value and check the value after setting.  If we didn't
    #really aquire the mutex, the value we get will be different from the
    #value we set
    $got_lock = $memcache->add($key, $lockval);
    if($got_lock) {
            $got_lock = $memcache->get($key);
            $got_lock = $got_lock === $lockval;
            if($got_lock) return true;
    }

    #the mutex was not acquired.  we must wait for it to be released
    $sleep_time = .01; #initial sleep time
    $sleep_time_increment = .05;
    $max_sleep_time=1; #maximum number of seconds to sleep between checking locks
    Instrumentation::get_instance()->timer();
    Instrumentation::get_instance()->increment('memcache_mutex_waits', 1);
    while(1) {
            usleep($sleep_time * 1000000);
            $sleep_time += $sleep_time_increment;
            if($sleep_time > $max_sleep_time) $sleep_time = $max_sleep_time;
            $exists = $memcache->get($key);
            if(!$exists) break; #mutex has been released
    }
    Instrumentation::get_instance()->increment('memcache_mutex_wait_time',   Instrumentation::get_instance()->timer());
    return false;
}

#NOTE - only the connection that acquired a mutex should release it.  there is no
#protection to ensure this is the case
function release_mutex($key, $memcache = false) {
    if($memcache === false) {
            #bring in memcache from global scope
            global $memcache;
    }

    $key = "LOCK::$key";
    return($memcache->delete($key));
}