我想知道在我的 Web 应用程序中使我的 Memcache 操作具有原子性的最佳方法是什么。
考虑以下场景:
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
在这种情况下,过程中没有原子性。
我的(潜在)解决方案是在我的应用程序中设置、获取和释放 key 锁定。
因此,在我实现后,上述过程将像这样工作:
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
想法?这种方法是否有效,是否会出现任何我应该警惕的性能问题?
最佳答案
考虑您要在这里解决什么问题。你:
大多数时候人们只想要(1)。如果这就是你想要的,你可以对
Memcached::cas()
使用检查和设置语义,或者如果你有一个简单的整数值,你可以使用原子 Memcached::increment()
和 Memcached::decrement()
操作。但是,如果您需要使用键来表示有限资源 (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);
}
与使用检查和设置方法相比,这种方法会导致更多的资源争用。
关于PHP 原子内存缓存,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10626904/