7

フォーラムを作成し、データベースの作業を節約するためにapcおよびmemcacheキャッシングソリューションを実装しています。

「Categories::getAll」などのキーを使用してキャッシュレイヤーの実装を開始しました。ユーザー固有のデータがある場合は、ユーザーIDなどのキーを追加して取得し"User::getFavoriteThreads|1471"ます。ユーザーが新しいお気に入りのスレッドを追加したら、キャッシュキーを削除すると、エントリが再作成されます。

ただし、ここに問題があります。

フォーラムにスレッドをキャッシュしたかったのです。非常に単純な「Forum::getThreads |$iForumId」。しかし...ページネーションを使用すると、これをいくつかのキャッシュエントリに分割する必要があります。たとえば

"Forum::getThreads|$iForumId|$iLimit|$iOffset".

誰かがフォーラムに新しいスレッドを投稿するまでは、これで問題ありません。"Forum::getThreads|$iForumId"制限とオフセットに関係なく、下のすべてのキーを削除する必要があります。

この問題を解決する良い方法は何でしょうか?一致しないものが見つかるまで、考えられるすべての制限とオフセットをループすることは本当にしたくありません。

ありがとう。

4

8 に答える 8

7

更新情報: データの使用に関する Josh の指摘は非常に優れていると判断しました。人々がフォーラムの 50 ページを閲覧し続ける可能性は低いです。

このモデルに基づいて、各フォーラムに最新の 90 のスレッドをキャッシュすることにしました。フェッチ関数では、制限とオフセットをチェックして、指定されたスレッドのスライスがキャッシュ内にあるかどうかを確認します。キャッシュの制限内にある場合は、array_slice() を使用して正しい部分を取得して返します。

このようにして、フォーラムごとに 1 つのキャッシュ キーを使用でき、キャッシュをクリア/更新する手間はほとんどかかりません :-)

また、リソースを大量に消費する他のクエリでは、キー間の関係を保存するフルンガブンガのモデルを使用したことも指摘しておきます。残念ながら、Stack Overflow では 2 つの回答を受け入れることができません。

ありがとう!

于 2008-09-22T07:46:45.050 に答える
5

memcacheグループからキー値へのハッシュテーブルを含む保護されたプロパティを持つカスタムクラス(ExtendedMemcacheなど)でクラスを拡張することで、これを解決することができました。

このExtendedMemcache->setメソッドは 3 つの引数 ( $strGroup$strKey$strValue) を受け入れます。set を呼び出すと、 と の間の関係が$strGroup保護$strKeyされたプロパティに格納され、続いて$strKeytoの$strValue関係がに格納されmemcacheます。

ExtendedMemcache次に、「deleteGroup」というクラスに新しいメソッドを追加できます。このメソッドは、文字列が渡されると、そのグループに関連付けられているキーを見つけて、各キーを順番に消去します。

http://pastebin.com/f566e913b すべてが理にかなっていて、うまくいくことを願っています。

PS。静的呼び出しを使用したい場合は、保護されたプロパティをmemcache独自のキーの下に保存できると思います。ちょっとした考え。

于 2008-09-20T23:19:13.860 に答える
5

また、労力と CPU コストの観点から、キャッシュ データを格納するコストと、キャッシュによって得られるものを比較することもできます。

フォーラム ビューの 80% がスレッドの最初のページを見ていることがわかった場合は、そのページのみをキャッシュすることを決定できます。これは、キャッシュの読み取りと書き込みの両方を実装するのがはるかに簡単であることを意味します。

ユーザーのお気に入りのスレッドのリストも同様です。これが各ユーザーがめったにアクセスしないものである場合、キャッシュはパフォーマンスをあまり向上させない可能性があります。

于 2008-09-21T03:31:12.083 に答える
2

あなたは本質的にビューをキャッシュしようとしていますが、それは常にトリッキーになります。データはめったに変更されないため、代わりにデータのみをキャッシュするようにしてください。フォーラムをキャッシュせず、スレッド行をキャッシュします。次に、db呼び出しは、キャッシュにすでにあるIDのリストを返すだけです。db呼び出しは、どのMyISAMテーブルでも高速になり、dbメモリを消費する大きな結合を行う必要がなくなります。

于 2008-09-20T21:48:46.963 に答える
1

考えられる解決策の1つは、フォーラム内のスレッドのキャッシュをページ分割するのではなく、スレッド情報をに配置することForum::getThreads|$iForumIdです。次に、PHPコードで、その特定のページに必要なものだけを引き出します。

$page = 2;
$threads_per_page = 25;
$start_thread = $page * $threads_per_page;

// Pull threads from cache (assuming $cache class for memcache interface..)
$threads = $cache->get("Forum::getThreads|$iForumId");

// Only take the ones we need
for($i=$start_thread; $i<=$start_thread+$threads_per_page; $i++)
{
    // Thread display logic here...
    showThread($threads[$i]);
}

これは、各ページでそれらを引き出すためにもう少し作業が必要であることを意味しますが、新しいスレッドの更新/追加時に1か所のキャッシュを無効にすることだけを心配する必要があります。

于 2008-09-20T21:49:05.213 に答える
1

測定するのが難しい事実を持たずに、この種の最適化を行う場合は十分に注意してください。

ほとんどのデータベースには、いくつかのレベルのキャッシュがあります。これらが正しく調整されている場合、データベースは、自分で実行できるよりも、キャッシュではるかに優れた仕事をする可能性があります。

于 2008-09-21T11:07:35.823 に答える
1

フルンガバンガへの対応:

グループ化を実装する別の方法は、グループ名とシーケンス番号をキー自体に入れ、シーケンス番号を増やしてグループを「クリア」することです。各グループの現在有効なシーケンス番号を独自のキーに保存します。

例えば

get seqno_mygroup
23

get mygroup23_mykey
<mykeydata...>
get mygroup23_mykey2
<mykey2data...>

次に、グループを単純に「削除」します。

incr seqno_mygroup

出来上がり:

get seqno_mygroup
24

get mygroup24_mykey
...empty

等..

于 2009-01-13T05:41:52.720 に答える
1

flungabunga: あなたのソリューションは、私が探しているものに非常に近いものです。私がこれを行うのを妨げている唯一のことは、各リクエストの後に関係を memcache に保存してロードし直す必要があることです。

これがどの程度のパフォーマンス ヒットを意味するかはわかりませんが、少し効率が悪いようです。いくつかのテストを行い、それがどのように機能するかを確認します。構造化された提案に感謝します (そして、そのために表示するいくつかのコード、ありがとう!)。

于 2008-09-20T23:47:57.643 に答える