コストのかかるクエリをキャッシュする必要があります(5秒)。最近、memcacheを使用する際のドッグパイルの影響について知りました。1つの解決策は、この影響を防ぐためにキャッシュのキーと値のペアのロックを使用することです。GAE memcachedはmemcachedキー値のロックをサポートしていないため、ドッグパイル効果を防ぐためのベストプラクティスは何ですか?
3 に答える
アプリの動作によって異なりますが、役立つ3つのアプローチがあります(すべてのシナリオに最適なものはなく、それぞれに欠点があります)。
「少し待ってから再試行してください」のようなものでリクエストに応答できる場合は、実際の値の再処理に時間を費やす前に、ミス時にそれを表すフラグをmemcacheに設定すると役立ちます( getと最初のセットの間で競合が発生する可能性がありますが、クエリが実行されるのを待つよりもはるかに短くなります):
value = memcache.get(key)
if value is None:
memcache.set(key, 'recalculating')
// do the slow thing
memcache.set(key, actual_result)
return value
または、キャッシュされた結果に有効期間を設定しているが、わずかに古いデータを受信するクライアントに対処できる場合は、タイムアウトとキーを使用して値をキャッシュするだけでなく、タイムアウトなしで別のキーを使用してコピーをキャッシュします。次に、ミスした場合は、このコピーを使用して、新しい値を再処理している間にキャッシュを再入力します(ここでも、get / set間の競合の可能性があり、コピーが削除される可能性もあります)。
value = memcache.get(key)
if value is None:
memcache.set(key, cache.get(key+'copy'))
// do the slow thing
memcache.set(key, actual_result, 30)
memcache.set(key+'copy', actual_result)
return value
3つ目はより単純で、バックエンドが常にクエリを実行し、キャッシュを更新するようにするだけで、フロントエンドリクエストがそれを実行する必要が少なくなります。ただし、これは、誰が使用している値に関係なく、クエリが実行されていることを意味します。
それを無視します。
Google Kool-Aidを飲んで、データストアにヒットする同時クエリからデータベースが大幅にスラッシングされることはないと信じてください。ドッグパイル効果はとにかく一時的なものであり、インフラストラクチャがそれを吸収する必要があります。さらにいくつかのクエリに対して支払うだけです。
あなたが実際に十分なトラフィックを持っていて、それがあなたにかなりのお金を費やしているのでない限り、それはおそらくあなたの優先順位をかなり下回っています。
セマフォロックを使用すると、ドッグパイル効果を防ぐことができます。値の有効期限が切れると、最初のプロセスがロックを取得し、新しい値の生成を開始します。以降のすべてのリクエストは、ロックが取得されているかどうかを確認し、古いコンテンツを提供します(取得されている場合)。新しい値が生成された後、ロックが解除されます。
キャッシュされた値には有効期間を延長する必要があります。これにより、有効期限が切れても物理的に削除されず、必要に応じて引き続き提供できます。
PHPでの動作は次のとおりです(Pythonで簡単に複製できるはずです)。
キャッシュストアからキャッシュ値を取得します。
$value = $this->store->get($key);
$valueは値オブジェクトです。
キャッシュされた値の有効期限が切れているかどうかを確認します。有効期限が切れていない場合は、提供してください。
if ($value && !$value->isStale()) {
return $value->getResult();
}
それ以外の場合は、ロックを取得して、新しい値を再生成するプロセスが1つだけになるようにします。
$lock_acquired = $this->acquireLock($key, $grace_ttl);
ロックを取得できない場合は、ロックを再生成している他のプロセスがすでに存在することを意味するため、現在の(古い)値を提供してみましょう。
if (!$lock_acquired) {
return $value->getResult();
}
それ以外の場合(ロックが取得されている)、新しい値を再生成します。
$result = ...
再生成された値をキャッシュストアに保存します。猶予期間を追加して、他のプロセスで必要な場合に古い結果が提供されるようにします。
$expiration_timestamp = time() + $ttl;
$value = new Value($result, $expiration_timestamp);
$real_ttl = $ttl + $grace_ttl;
$this->store->set($key, $value, $real_ttl);
ロックを解除します。
$this->releaseLock($key);
完全なPHP実装:https ://github.com/sobstel/metaphore/blob/master/src/Cache.php 。MintCacheを試すこともできます:https ://djangosnippets.org/snippets/155/ 。