2012-05-16 2 views
2

Im интересно, что является лучшим способом сделать мой Memcache операций atmoic в моем веб-приложении.PHP Atomic 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 

В этом случае нет атомарность в этом процессе.

Мое (потенциальное) решение состоит в том, чтобы устанавливать, приобретать и выпускать блокировки ключей из моего приложения.

Так вышеописанный процесс будет работать, как это после моей реализации:

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 

Мысли? Будет ли этот метод работать, и будут ли какие-либо успехи в производительности, о которых я должен опасаться?

ответ

5

Рассмотрите, какую проблему вы пытаетесь решить. Вы:

  1. просто хотите избежать проблемы с потерянным обновлением. (Например, с помощью счетчика, который увеличивается на единицу.)
  2. или вы делаете потребность в обеспечить, что в то время как один клиент извлечет значению элемента, никакой другой клиент не может использовать это значение? (Здесь значения представляют собой ограниченный ресурс.)

Большую часть времени люди просто хотят (1). Если это все, что вам нужно, вы можете использовать семантику check-and-set с Memcached::cas(), или если у вас есть простое целочисленное значение, вы можете использовать операции атома и 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); 
} 

Такой подход приводит к гораздо больше ресурсов, чем утверждение, вы получите с чековой и множественному подходу.

+0

К сожалению, модификации не будут такими же простыми, как приращение на 1. В случае, когда кредиты добавляются или вычитаются из переменных сумм, мне нужно абсолютное атомарность в этом процессе. Второй вариант похож на мое (потенциальное) решение. – Kovo

+2

Лучшим решением является 'cas()'. Второе лучшее решение - использовать два ключа: '$ keyname' и' $ keyname.'_ lock''. Используйте 'add()/delete()' для получения/освобождения блокировки. –

1

Существует встроенная функция, которая может позаботиться об этом для вас уже. То, что вы ищете, это CAS (проверка и установка).

«КАС» является проверка и устанавливается операция, которая означает «хранить эти данные, но только если никто другой не обновил, так как я в последний раз принес его.» 1

При попытке сохранить данные, которые ранее были обновлены другим процессом, то вызов set потерпит неудачу так, то вы можете решить, если вам необходимо повторно извлечь данные, хранить его в любом случае, или выручить.

См. Memcached::cas() для получения дополнительной информации.

Надеюсь, что это поможет.

+0

Спасибо, но я использую библиотеку memcache, а не библиотеку memcached:/ – Kovo

+2

Я вижу, извините. memcached - это новая клиентская библиотека для PHP для связи с серверами memcached, memcache теперь старая. [Этот ответ] (http://stackoverflow.com/a/1442747/892493) описывает некоторые новые функции в Memcached. Я бы рекомендовал переключиться на использование расширения php memcached, если это возможно, или вам придется свернуть свое собственное решение, чтобы сделать что-то, что уже встроено в демон memcached. – drew010

+0

Yup, я так понял. К сожалению, обновление не возможно atm – Kovo

Смежные вопросы