Memcachedの使用:データベースを更新するときにキャッシュを更新することをお勧めしますか?


13

この質問は、アーキテクチャのベストプラクティスに関するものです。

現在のアーキテクチャ

ユーザー情報のためにMySQLにアクセスするPHPクラスがあります。それを呼び出しましょうUserUserに何度もアクセスされるため、負荷を軽減するためにキャッシュのレイヤーを実装しました。

最初のレイヤーは、「リクエストごと」キャッシュと呼ばれるものです。MySQLからデータを取得した後、データをのプライベートプロパティに保存しますUser。データに対する後続のリクエストは、MySQLからデータを再リクエストする代わりにプロパティを返します。

Webリクエストはリクエストごとに存続および終了するため、このキャッシュは、アプリケーションが1回のリクエストでMySQLに複数回アクセスすることを防ぎます。

2番目のレイヤーはMemcachedです。プライベートプロパティが空の場合、最初にMemcachedでデータを確認します。Memcachedが空の場合、MySQLにデータを照会してMemcachedを更新し、のプライベートプロパティを更新しますUser

質問

私たちのアプリケーションはゲームであり、いくつかのデータが可能な限り最新であることが不可欠な場合があります。約5分間で、ユーザーデータの読み取り要求が10回または11回発生する場合があります。その後、更新が行われる場合があります。後続の読み取り要求は最新である必要があります。そうしないと、ゲームの仕組みが失敗します。

そのため、データベースの更新が発生したときに実行されるコードを実装しました。このコードは、更新されたデータを使用してMemcachedのキーを設定するため、Memcachedへの後続のリクエストはすべて最新です。

これは最適ですか?このような「リビングキャッシュ」のようなものを維持しようとするとき、パフォーマンスの問題やその他の「注意点」を知っておく必要がありますか?


これはデータの削除と再追加と何の関係がありますか?
マイクナキス

質問のタイトルを明確にしました。
スティーブン

キャッシュされたデータをただ期限切れにしないのはなぜですか?それを更新するということは、更新を確実に維持する必要があることを意味します(したがって、この方法で新しいデータを更新する必要がある場合は、更新を変更し続ける必要があります)。キャッシュの期限が切れると、すべてがデータベースから新たにプルされます---そして、新しい更新は更新コードへの新しい変更を必要としません。欠点は、データベースの負荷が高くなる可能性があることです。
ピーターK.

@ピーターええ、私たちもそれについて考えました。現在のアプローチで他の問題が発生しない場合は、それを使い続けます。それ以外の場合は、説明したとおりに処理する場合があります。
スティーブン

1
@Stephenあなたが説明するアプローチは「キャッシュ経由の書き込み」と呼ばれ、かなり一般的なアプローチです。
スリパティクリシュナン

回答:


10

私の推奨事項は、使用プロファイルとキャッシュの要件を確認することです。

古いデータをmemcachedに残す理由はわかりません。適切なアプローチ、つまりDBの更新を選択したと思います。

いずれにせよ、DB更新のラッパーが必要になります(これは実行済みです)。DBおよびRAM内のユーザーを更新するためのコードは、memcachedへのプッシュ、またはmemcachedでの期限切れも行う必要があります。

たとえば、ユーザーが通常ログオフの一部としてセッションごとに1回更新を行う場合、キャッシュ内のデータを更新することはあまり意味がありません(例:高得点合計)-すぐに期限切れにする必要があります。

ただし、データ(たとえば、現在のゲームの状態)を更新し、0.2秒後にデータを要求するPHPページがすぐにヒットする場合は、キャッシュに新しいものが必要です。


3

あなたが概説したように私はそれについては行きません。必要なのは、実際に完全に最新のデータが必要かどうかを判断することです。次に、必要な場合は、常にデータのどの部分を最新にする必要があるかを決定し、アーキテクチャ内にキャッシュできるものから分離します。

たとえば、ユーザーのメールアドレスを変更したらすぐに更新する必要があるため、間違ったアドレスにメールを送信することはありませんが、ユーザーの生年月日または姓を完全に変更する必要はほとんどありません。適切なユーザーエクスペリエンスを提供するための最新情報。(注:どんな種類のゲームを狙うべきかわからないので、ゲームアーキテクチャの例を使用していません。これはかなり理解しやすいと思います)。

このように、2つの明確なデータセットがあります。短期および長期のキャッシュ可能なデータです。おそらく、DBの負荷を軽減するために、短期データでは1分程度のキャッシュ期間で逃げることができますが、長期データは、スライド期間でキャッシュ内に残しておくことができます中古。

次に、更新に対処する必要があります。最初に、DBトリガーを使用して、古いアイテムをキャッシュから単純に削除することを検討します。これにより、次にデータを要求するときにビジネスレイヤーがキャッシュの更新をトリガーし、データが使用されていない場合(たとえば、ユーザーが電子メールアドレスを変更してすぐにログアウトする場合)にキャッシュの領域を解放します。これによりUIのパフォーマンスの問題が発生する場合(つまり、キャッシュの更新を待機しているときに非常に多くの遅延が発生する場合)、アイテムがキャッシュから削除されたときにキャッシュ呼び出しをトリガーするだけです。また、この小さなデータセットのDB読み取り時間の最適化を検討して、キャッシュの更新で生じる遅延が最小限になるようにします(本当に必要なデータのみをロードする必要があるため、これは簡単です)。

どんな状況でも、私がやらないことは、キャッシュを埋める追加のメソッドを追加することです。そのため、2つの場所で呼び出し(およびAPIフックなど)を維持する必要があります。

落とし穴については、キャッシュに直接書き込む場合に注意する必要がある主なことは同期です。サイレント更新中に多くのスレッドが読み取りを試みると、いくつかの深刻な無効なデータの問題が発生する可能性があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.