4

Webアプリで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

考え?この方法は機能しますか?また、注意が必要なパフォーマンスへの影響はありますか?

4

2 に答える 2

7

ここで解決しようとしている問題を考えてみましょう。あなたは:

  1. 更新が失われる問題を回避したいだけです。(たとえば、1 ずつインクリメントするカウンターを使用します。)
  2. または、あるクライアントがアイテムの値を取得している間、他のクライアントがその値を使用できないようにする必要がありますか? (これは、値が限られたリソースを表す場所です。)

ほとんどの場合、人々はただ (1) を望んでいます。これだけで十分な場合は、check-and-set セマンティクスをMemcached::cas()で使用できます。または、単純な整数値がある場合は、atomicMemcached::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()、2 つのキーと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);
}

このアプローチでは、チェック アンド セットのアプローチよりもはるかに多くのリソース競合が発生します。

于 2012-05-16T21:49:05.557 に答える
2

すでにこれを処理できる機能が組み込まれています。あなたが探しているのはCAS(チェックアンドセット)です。

「cas」は、「このデータを保存しますが、最後に取得してから他の誰も更新していない場合にのみ保存する」ことを意味するチェックおよび設定操作です。1

以前に別のプロセスによって更新されたデータを保存しようとすると、 への呼び出しsetが失敗するため、データを再取得する必要があるか、とにかく保存するか、または救済するかを決定できます。

詳細については、 Memcached::cas()を参照してください。

それが役立つことを願っています。

于 2012-05-16T21:30:31.110 に答える