web-dev-qa-db-ja.com

Memcachedの使用:データベースの更新時にキャッシュを更新することは良い習慣ですか?

この質問は、アーキテクチャのベストプラクティスについてです。

現在のアーキテクチャ

私はPHPクラスにMySQLにアクセスしてユーザー情報を取得します。これをUserと呼びましょう。Userは何度もアクセスされるため、キャッシュのレイヤーを実装しました負荷を減らします。

最初のレイヤーは、「リクエストごと」のキャッシュと呼ばれるものです。 MySQLからデータを取得したら、Userのプライベートプロパティにデータを格納します。以降のデータ要求では、MySQLからデータを再要求するのではなく、プロパティを返します。

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

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

質問

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

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

これは最適ですか?このような一種の「生きているキャッシュ」を維持しようとする際に気をつけるべきパフォーマンスの問題やその他の「落とし穴」はありますか?

13
Stephen

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

古いデータをmemcachedに残す理由はわかりません。私はあなたが正しいアプローチ、つまりDBを更新することを選んだと思います。

いずれにしても、DB更新(実行済み)のラッパーが必要になります。 DBとRAM内のユーザーを更新するコードは、memcachedへのプッシュも行う必要がありますOR memcachedでの有効期限切れ。

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

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

10
jasonk

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

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

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

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

どのような場合でも、キャッシュ(およびAPIフックなど)を2か所で維持する必要があるため、キャッシュを埋めるメソッドを追加することはしません。

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

3
Ed James