20

私はキャッシング (主に redis と memcached) を調べてきましたが、データが絶えず変化しているときにキャッシングを正確に使用する場所を見つけるのに苦労しています。

Twitter を例にとります ( Twitter を 10000% 速くする を読んでください)。データベース レコードの大部分が絶えず変更されている場合、どのようにデータをキャッシュしますか (またはキャッシュしますか?)

Twitter には次のモデルがあるとします: UserTweet、。FollowFavorite

1 日に 1 回リツイートされるツイートを投稿する人もいれば、1 日に 1000 回リツイートされるツイートを投稿する人もいます。その 1000 回のリツイートの場合、24 * 60 == 14401 日は約数分あるため、ツイートがほぼ毎分更新されたことを意味します (440 のお気に入りも獲得したとします)。誰かをフォローするのと同じように、チャーリー・シーンは1 日で 100 万人の Twitter フォロワーを獲得しています。このような場合にキャッシュする価値はないように思われますが、まだそのレベルに達していないためかもしれません。

また、平均的な Twitter フォロワーは、少なくとも 1 日に 1 回はツイート/フォロー/お気に入りのいずれかを行っているとします。つまり、単純な intro-rails スキーマの場合、users テーブルは少なくとも 1 日に 1 回更新されます (tweet_countなど)。このケースは、ユーザー プロファイルのキャッシュに適しています。

しかし、上記の 1000x ツイートと 100 万人のフォロワーの例では、データのキャッシュに関して推奨される方法は何ですか?

具体的には (memcached または redis を想定し、純粋な JSON API (ページ/フラグメント キャッシュなし) を使用する場合):

  • 個々のツイート/記録をキャッシュしますか?
  • それとも、ページネーションを介してレコードのチャンクをキャッシュしますか (たとえば、それぞれの redis リスト20)?
  • それとも、両方のレコードを個別に、またはページでキャッシュしますか (単一のツイートと JSON フィードを表示する場合)?
  • それとも、ホーム タイムラインのツイート、ユーザーのツイート、ユーザーのお気に入りのツイートなど、さまざまなシナリオごとにツイートのリストをキャッシュしますか? それとも上記のすべてですか?
  • または、データを「最も揮発性が高い (最新)」から「過去数日」、「古い」チャンクに分割します。「古い」データは、より長い有効期限でキャッシュされるか、個別のページ分割されたリストなどにキャッシュされますか? そして、最新のレコードはまったくキャッシュされません。(つまり、データがツイートのように時間に依存している場合、古いレコードがそれほど変化しないことがわかっている場合、別の方法で処理しますか?)

私が理解していないのは、データの変更量とキャッシュする必要がある場合の比率です (そして、キャッシュの有効期限が切れる複雑さに対処します)。Twitter は、さまざまなユーザーのツイート フィードとユーザーごとのホーム ツイートをキャッシュしているように見えますが、1 つのお気に入り/ツイート/リツイートのたびにキャッシュを無効にすると、それらすべてのキャッシュ アイテム (およびキャッシュされたレコードのリスト) が更新されることになります。ある時点で、キャッシュを無効にすることは非生産的であることを意味するように思えます。

このように大きく変化しているデータをキャッシュするための推奨される戦略は何ですか?

4

2 に答える 2

4

Twitter がこのようなことをしているとは言いませんが (関連していると確信していますが)、最近、CQRS + Event Sourcingに精通しました。( http://martinfowler.com/bliki/CQRS.html + http://martinfowler.com/eaaDev/EventSourcing.html ) .

基本的に: 読み取りと書き込みは、アプリケーションと永続性レベル (CQRS) で完全に分離され、システムへのすべての書き込みは、サブスクライブできるイベントとして処理されます (イベント ソーシング)。まだまだあります (イベント ストリーム全体を再生できるなど、後で新しい機能を実装するのに非常に役立ちます) が、これは重要な部分です。

これに続いて、一般的な慣行は、責任がある(つまり、新しい読み取りモデルにイベントを投影する)がサブスクライブしているイベントタイプの新しいイベントを受け取るRead Modelたびに、(メモリ内キャッシュを考えてください)が再作成されることですProjector.

この場合、イベントは TweetHandled でありRecentTweetsPerUserProjectorTimelinePerUserProjector、 などのすべてのサブスクライバーによって処理され、それぞれの ReadModel が更新されます。

結果は、最終的に一貫性があり、無効化を必要としない ReadModel のコレクションです。つまり、更新された書き込みと結果のイベントが、最初に ReadModel を更新するためのトリガーになります。

最終的に、チャーリー シーンの読み取りモデルは頻繁に更新されることに同意します (ただし、この更新は非常に効率的です)。そのため、キャッシュ アドバンテージはおそらくかなり低くなります。ただし、平均的なユーザーの時間単位あたりの平均投稿を見ると、状況はまったく異なります。

DDD / CQRS / イベント ソーシング シーンで影響力のある人物: Greg Young、Udi Dahan。

概念はかなり「深遠」なので、1 時間で完全に理解できるとは思わないでください (少なくとも私は知りませんでした)。おそらく、関連する概念に関するこの最近のマインドマップも役立つでしょう: http://www.mindmeister.com/de/181195534/cqrs-ddd-links

ええ、あなたがまだ気づいていないなら、私はこれについてかなり熱心です:)

于 2012-07-24T18:26:03.213 に答える
1

私の控えめな 2 セント: Redis を使用すると、そのデータ構造を操作できます。つまり、リレーショナル データベースに毎回触れるよりも高速にメモリ内操作を実行できます。

そのため、「キャッシュ」を変更して、期待どおりに無効にしないようにすることができます。

私のプロジェクトでは、定期的に 50 万件のレコードをソート済みセットにロードし、それらに対して範囲クエリを実行するだけで統計レポートを実行しました。これにより、レポートの実行時間が平均 2 秒未満になりました。

于 2012-07-24T16:57:06.560 に答える