2012-05-16 2 views
2

Im 내 웹 앱에서 Memcache 작업을 기동하지 못하게하는 가장 좋은 방법은 무엇인지 궁금합니다.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)을 원합니다. 이 모든 것이 원하는 경우 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 (check and set)입니다.

"CA는" "하지만 내가 마지막으로 가져온 이후로 아무도 다른 사람 업데이트되지 않은 경우에만.이 데이터를 저장"을 의미 체크 및 설정 작업입니다 이전에 다른 프로세스에 의해 업데이트 한 데이터를 저장하려고하면 1

, set에 대한 호출이, 당신은 데이터를 다시 가져 오기 위해 필요한 경우 다음 결정할 수 있도록 실패 어쨌든 그것을 저장하거나됩니다 구제하자.

자세한 내용은 Memcached::cas()을 참조하십시오.

희망이 있습니다.

+0

감사합니다.하지만 memcached 라이브러리가 아닌 memcache 라이브러리를 사용하고 있습니다./ – Kovo

+2

죄송합니다. memcached는 memcached 서버와 통신하기위한 PHP 용 최신 클라이언트 라이브러리이며, memcache는 이제 구식입니다. [이 답변] (http://stackoverflow.com/a/1442747/892493) Memcached의 몇 가지 새로운 기능을 설명합니다. 가능한 경우 PHP memcached 확장을 사용하도록 전환하는 것이 좋습니다. 또는 이미 memcached 데몬에 내장되어있는 작업을 수행하기 위해 자체 솔루션을 롤백해야합니다. – drew010

+0

그래, 나는 많이 생각했다. 불행하게도 그것을 업데이트하는 것은 불가능합니다. – Kovo