巧妙なキャッシュの削除(php 5 + Mongodb + memcached)

まえがき



現在、非常に多くの負荷の高いプロジェクトが存在するため、キャッシングのトピックはこれまで以上に重要になります。 データベースクエリ、個々のページブロック、およびすべてのページの両方がキャッシュされます。



私にとっては、データベースへのクエリの結果のみをキャッシュすることにしました。なぜなら、私見では、キャッシュを巨大な(またはそうではない)htmlブロックでロードすることは、何らかの方法でリソースを浪費するからです。 (このステートメントは、テンプレートエンジンを使用していない場合にのみ当てはまります)。 そしてもちろん、よく知られているmemcachedをキャッシングサービスとして使用します。

次に、このようなキャッシングでどのような問題が待ち受けているかを見てみましょう。

そして、問題はただ1つですが、最も個人的な問題ではありません-キャッシュの維持は常に最新です。



カットの下-問題に対する私の解決策、キャッシュが永遠に生きることを可能にします(もちろん、関連性があり、RAMを使い果たしていない限り)。





詳細



現在ファッショナブルなMVCモデルに準拠して、データベースへのすべてのクエリはモデル内で実行されます。 サイトの各セクションのプロジェクトには、独自の個別のモデルと、各セクションで必要なデータを含む一般的なモデルがあります。



この方法でのキャッシュエントリキーは、セクションの名前、関数の名前、およびこの関数に渡されるパラメーターで構成されます。 これはすべて、md5でラップアラウンドして、長すぎるストリームを防止したり、キャッシュキーの一部としてパラメーターの配列を渡したりします。



現在、90%のケースでデータベースの情報を更新すると、リセットする必要がある関数のキャッシュが確実にわかります。 しかし、これは常に起こるとは限りません。 たとえば、ユーザーは個人アカウントから最後の5つのメッセージを削除しましたが、すべてのメッセージが破損しているため(たとえば、ページごとに10)、最後のページのキャッシュのみをリセットするため、他のすべてのページは古い状態でキャッシュされたままになり、これはもはや役に立ちません。 タスクは、パラメータ(ユーザーID)を1つだけ知っているが、2番目(ページ番号)を知らない関数キャッシュをリセットすることです。



だから私の決定



簡単に言うと、新しいエントリがキャッシュに追加されるたびに、キーのコンポーネントがmongoに記録されるため、その部分のみを知って、キャッシュキーを完全に再作成することができます。 詳細については説明しませんが、コードを調べます。

class Cache extends Memcached { private $registry; public function __construct() { parent::__construct(); $this->addServer('localhost', 11211); $m = new Mongo(); $this->registry = $m->local->cache_registry; // ,      } public function set($name, $content) { //    $this->registry->insert(array('id' => $name)); parent::set(md5(print_r($name, 1)), $content); } public function delete($name) { //    $this->registry->remove(array('id' => $name)); parent::delete(md5(print_r($name, 1))); } public function get($name) { return parent::get(md5(print_r($name, 1))); } public function smart_delete($params) { //    $criteria = array(); $size = sizeof($params); for ($i = 0; $i < 2; $i++) { //       $criteria['id.' . $i] = $params[$i]; } if ($size == 3) { //     for ($i = 0; $i < sizeof($params[2]); $i++) { $criteria['id.2.' . $i] = $params[2][$i]; } } elseif ($size > 3) throw new Exception('Size of input parameters is out of expected range'); $cursor = $this->registry->find($criteria); while ($cursor->hasNext()) { //          $data = $cursor->getNext(); $id = $data['_id']; parent::delete(md5(print_r($data['id'], 1))); $this->registry->remove(array('_id' => new MongoId($id))); } } }
      
      







そして、呼び出しの例、すべてが最終的に適所に落ちたように:

 $cache = new Cache(); $cache->smart_delete('user', 'messages', array(1));/*    messages   user    = 1*/
      
      







ご覧のとおり、これは非常に単純で非常に多くの利益があります。

  1. 特定のセクションからすべてのエントリを削除します
  2. 関数名のみによるすべてのセクションエントリの削除
  3. すべての関数エントリを削除し、必要なパラメーターのみを知り、不要なパラメーターを破棄します。




もちろん、現在実装されているという事実にもかかわらず、レコードを削除することはできません。2番目のパラメーターのみを知っており、最初のパラメーターを知らないため、関数の作成時にパラメーターの順序を検討する必要があります。 または、異なるセクションから同一の関数のレコードを削除します(理由はわかりません)が、空き時間があれば、これはすべて実現可能だと思います。



PS過去の休日のすべて!



All Articles