PHP Atomic Memcache

时间:2012-05-16 21:21:36

标签: php memcached

我想知道在我的网络应用程序中使我的Memcache操作atmoic的最佳方法是什么。

考虑以下情况:

Client 1 connects and retrieves data from key 1
Client 2 connects a few microsecond after Client 1, requests the same data from key 1
Client 1 saves new data to key 1
Client 2 saves new (different data) to key 1, not taking into account that Client 1 modified the value already

在这种情况下,过程中没有原子性。

我的(潜在)解决方案是在我的应用程序中设置,获取和释放键上的锁。

因此,在我实施之后,上述过程将如下所示:

Client 1 connects, checks for an active lock on key 1, finds none, and gets the data
Client 2 connects a few microsecond after Client 1, requests the same data from key 1, but finds a lock
Client 2 enters a retry loop until Client 1 releases the lock
Client 1 saves new data to key 1, releases the lock
Client 2 gets the fresh data, sets a lock on key 1, and continues

思考?这种方法是否有效,是否会有任何性能点击我应该警惕?

2 个答案:

答案 0 :(得分:5)

考虑一下你在这里要解决的问题。你:

  1. 只是想避免丢失更新问题。 (例如,增加一个计数器。)
  2. 或者需要 确保当一个客户端检索到某个项目的值时,没有其他客户端可以使用该值吗? (这是值代表有限资源的地方。)
  3. 大多数时候人们只想要(1)。如果这是你想要的全部,你可以使用Memcached::cas()的检查和设置语义,或者如果你有一个简单的整数值,你可以使用原子Memcached::increment()Memcached::decrement()操作。 / p>

    但是,如果您需要使用密钥来表示有限资源(2),请考虑使用一组不同的语义:

    $keyname = 'key_with_known_name_representing_finite_resource';
    
    // try to "acquire" the key with add().
    // If the key exists already (resource taken), operation will fail
    // otherwise, we use it then release it with delete()
    // specify a timeout to avoid a deadlock.
    // timeout should be <= php's max_execution_time
    if ($mcache->add($keyname, '', 60)) {
       // resource acquired
       // ...do stuff....
       // now release
       $mcache->delete($keyname);
    } else {
       // try again?
    }
    

    如果由于某种原因您无法访问cas(),则可以使用两个密钥实现锁定add() / delete

    $key = 'lockable_key_name';
    $lockkey = $key.'##LOCK';
    
    if ($mcache->add($lockkey, '', 60)) { // acquire
        $storedvalue = $mcache->get($key);
        // do something with $storedvalue
        $mcache->set($key, $newvalue);
        // release
        $mcache->delete($lockkey);
    }
    

    与使用检查和设置方法相比,这种方法导致更多的资源争用。

答案 1 :(得分:1)

内置功能可以为您解决此问题。您正在寻找的是CAS(检查和设置)。

  

“cas”是一个检查和设置操作,意味着“存储此数据但是   只有在我上次提取它之后没有其他人更新过。“ 1

当您尝试存储之前由其他进程更新的数据时,对set的调用将失败,因此您可以决定是否需要重新获取数据,无论如何都要存储数据,或者拯救

有关详情,请参阅Memcached::cas()

希望有所帮助。