キャッシュは速い。キー・バリュー・アクセスに最適化されたインメモリ・システムを使えば、クライアントが計測するp99のレスポンスタイムはミリ秒以下です。とても速いので、キャッシュは楽しくもあります。ユーザーをイライラさせる高遅延のエクスペリエンスと、リピーターを生み出すスムーズで楽しいエクスペリエンスとの違いになり得ます。
しかし、キャッシュは足かせにもなる。キャッシュには効果的な使い方もあれば、非効果的な使い方もあります。非効果的なキャッシュ戦略よりもさらに悪いのは、有害なキャッシュ戦略です。
では、どのようにすれば、顧客に喜ばれ、足手まといにならないキャッシング戦略を取ることができるのでしょうか?2回のブログでお答えします。2回目は、あなたのアプリケーションにおけるキャッシュの実際の戦略とパターンを取り上げます。この最初のブログでは、あなたの戦略を決定する3つの重要な選択肢を取り上げます:
- Where to cache: local vs. remote
- When to cache: read vs. write
- How to cache: inline vs. aside
キャッシュする場所-ローカル・キャッシュとリモート・キャッシュ
キャッシュについて考えるとき、私たちはしばしば、より高速で耐久性の低いバージョンのデータベースのように使用される集中型のリモート・キャッシュに飛びつく。しかし、キャッシュは独立したインフラである必要はありません。バックエンドサーバー上であれ、ユーザーのブラウザ上であれ、アプリケーションにローカルにキャッシュを追加することができます。ローカル’キャッシュというのは、あるコンピュートに対してローカルで、他のコンピュートインスタンスからアクセスできないキャッシュを意味する。
一般的に、ローカル・キャッシュかリモート・キャッシュかという問題は、ユーティリティかシンプルさかということに帰着します。ローカルキャッシュは通常、新しいインフラを導入するよりもアプリケーションに追加する方が簡単です。さらに、新しいインフラストラクチャーは、可用性とアプリケーションのアップタイムに関する追加的な課題をもたらしますが、ローカルキャッシュは一般的にそれを避けることができます。
一方、ローカル・キャッシュは集中型キャッシュよりも使い勝手が悪いのです。バックエンドサーバーでキャッシュしている場合、リクエストが以前にデータをキャッシュしたマシンによって処理される可能性は、フリートのサイズが大きくなるにつれて低くなります。最近のクラウドベースのアプリケーションは刹那的であるため、これはさらに真実です。サーバーレス機能、コンテナ、インスタンスは、アプリケーションが需要に合わせて動的にスケールアップしたりスケールダウンしたりするため、ますます短命になりつつあります。アプリケーションの新しいインスタンスにはローカルキャッシュがないため、アプリケーションへの最初のリクエストには何のメリットもありません。
最後に、ローカル・キャッシュでは、古いデータの管理が難しくなる可能性があります。データが変更されたり削除されたりした場合、一元化されたリモート・キャッシュにあるキャッシュ・データに対応する更新を行うのは簡単です。ローカル・アプリケーション・インスタンスやクライアント・ブラウザに分散されているキャッシュ・データの更新を指示するのは、より難しくなります。このため、ローカルキャッシュは、特定のタイプのキャッシュデータ、または低いTTL(time-to-live)コンフィギュレーションでのみ機能する可能性があります。
リモートの集中型キャッシュには、このような欠点はありません。リモート・キャッシュは、ある作業を処理するどのサーバーでも使用することができ、アプリケーションにとってより広く有用なものとなります。さらに、リモート・キャッシュは一般的にオンデマンドでデータを失効させるメカニズムを持っており、書き込みパスが変更された後にデータをパージすることができます。リモート・キャッシュの欠点は、インフラストラクチャの別個の部分を維持する運用上の課題が中心です(ただし、Momento Cacheがこの問題を解決していることは注目に値します)。キャッシュの場所についてもっと深く知りたい方は、私が書いた別のブログをご覧ください: キャッシュの種類を理解する。
キャッシュするタイミング:リード・キャッシュとライト・キャッシュ
ここでも、2つの選択肢があります:最初の読み込み時にデータをキャッシュするか(しばしば「レイジーローディング」と呼ばれる)、書き込み時にデータをキャッシュするか、です。
最も一般的なキャッシュ・パターンは、リード・アサイド・パターンでしょう。パターンでは、アプリケーションはまずリクエストに対してキャッシュからデータを読み込んで返そうとします。データがキャッシュにない場合、アプリケーションはデータを読み込むためにデータベースにフォールバックします。そして、レスポンスを返す前にデータをキャッシュに保存し、そのデータを必要とする次のリクエストで利用できるようにします。
逆のパターンは、書き込みが成功した後にキャッシュをロードすることです。書き込みが成功したら、その書き込みがすぐに使われることを予期して、積極的にキャッシュにプッシュします。
読み込み時にデータをキャッシュする利点は、柔軟性とスペース効率です。レイジーローディングは、ほとんどすべてのデータセットに対応できる柔軟なパターンです。個々のオブジェクト、複数のオブジェクトからなる結果セット、あるいは集約された値をキャッシュするために使うことができます。データベースから直接結果をキャッシュする場合でも、計算後の結果をキャッシュする場合でも、クライアントに返す前に最終的なレスポンスをキャッシュするだけなので、リードアサイドキャッシングの実装は簡単です。
これは、書き込み側でプロアクティブにキャッシュを行う場合、より難しくなります。書き込み時に個々の項目をキャッシュするのは簡単ですが、結果セットや集約された値をプロアクティブにキャッシュするのはより困難です。
さらに、レイジー・ローディングは、キャッシュをよりスペース効率よく使うことができます。再度読み込まれるかどうかに関係なく、書き込み時にデータをキャッシュにロードするのではなく、一度読み込まれたデータだけをキャッシュするのです。多くのアプリケーションでは、個々のデータの読み取りは時間的に相関しています。一度読み込まれたものは、その後すぐに読み込まれる可能性が高くなります。少なくとも一度リクエストされたデータだけをキャッシュすることで、より頻繁にアクセスされるデータをキャッシュするように最適化されます。
データを読み込むときにキャッシュすることの欠点は、最初の読み込みが遅くなることと、古いデータが返される可能性があることです。キャッシュを読み込むのはデータが読み込まれたときだけなので、要求されたデータはそれぞれ、より遅い、キャッシュされていないパスを介して少なくとも1回リクエストする必要があることを意味します。アプリケーションのニーズによっては、これは最適ではないかもしれません。
さらに、読み取り側でデータをキャッシュするだけのパターンでは、クライアントに古いデータを返すことになります。キャッシュされたデータが消去されないまま、基礎となるデータが変更された場合、ユーザーは混乱した結果を見ることになります。アプリケーションはデータを短時間キャッシュすることでこれを軽減することができるが、キャッシュ・ミスが発生した場合、上述のマイナス面を悪化させることになります。
キャッシュの方法:インライン・キャッシングとサイド・キャッシング
前のセクションでは、リード・アサイド・キャッシュについて説明しました。asideキャッシュは最も単純なタイプのリモートキャッシュで、サービスから明示的に与えられたデータを保存します。通常、単純なgetとsetのセマンティクスを持ち、欲しいデータを柔軟に保存することができますが、そのデータを特別に保存する必要があります。データがキャッシュに存在しない場合、あなたのサービスは他の場所で基礎となるデータを見つけ、必要であればキャッシュを更新する責任があります。
一方、インライン・キャッシュは、データを取得するために呼び出すサービスからは透過的なキャッシュです。アプリケーションはインラインキャッシュに直接アクセスしてアイテムを取得します。キャッシュが要求されたデータを持っていない場合、キャッシュ自身が上流のデータソースからデータを取得します。
これらのキャッシュがなぜこのような名前なのかは、以下のアーキテクチャ図を見ればわかるでしょう。アサイド・キャッシュはアプリケーションの脇に置かれ、データ・ソースとは別に呼び出されます。あるいは、インライン・キャッシュは、データ・ソースへのリクエストとインラインで使用されます。
ほぼすべてのユースケースに柔軟に対応できるため、アサイド・キャッシュの方が一般的です。さらに、最終的なデータストアから切り離されているため、キャッシュレイヤーでどのように障害を処理するかを選択することができます。
インライン・キャッシュの利点は、アプリケーション内がシンプルになることです。アプリケーションは、複数の異なるストアや、キャッシュミスが発生した場合にデータベースにフォールバックするための対応するロジックについて心配する必要はありません。
インラインキャッシュの欠点は、アプリケーションの可用性が下がることです。キャッシュ機能を追加するだけでなく、データベースとの通信も担当するインフラを追加することになります。キャッシュがダウンした場合、キャッシュ自体がデータベースと通信していたため、データベースにフォールバックするのが難しくなるかもしれません。
インラインキャッシュのもう一つの欠点は、そのようなサービスが利用できるかどうか、です。インライン・キャッシュは、フロントとなるダウンストリーム・データ・ソースと緊密に統合されています。そのため、誰かがプライマリー・データ・ソースと統合するキャッシュを特別に構築する必要があります。このため、インライン・キャッシュは一般的に汎用プロトコルか、特定のデータベースへの独自のアドオンとして予約されています。
結論
キャッシングの主要な選択肢を検討することは、ユースケースに適したキャッシング戦略を決定する重要なステップです。次回のブログでは、実際のキャッシュ戦略とパターンを取り上げますので、お楽しみに!
リモートで集中管理されたリード・アサイド・キャッシュでありながら、運用上の課題が全くないのであれば、Momento Cacheは最適でしょう。ニーズが異なる場合でも、弊社に連絡を取り、ユースケースについて話し合い、ソリューションを見つけることができます。