メニュー
Amazon ElastiCache
ユーザーガイド (API Version 2015-02-02)

キャッシュ戦略

このトピックでは、キャッシュを入力して維持する戦略について説明します。

キャッシュするデータとデータへのアクセスパターンに基づいて、キャッシュを入力し維持するために実装する戦略です。たとえば、おそらくゲームサイト、Facebook の投稿、トレンドのニュースのランキングトップ 10 で同じ同じ戦略は使用したくないでしょう。このセクションの後半では、一般的なキャッシュのメンテナンス戦略、利点および欠点について説明します。

遅延読み込み

その名前が示すようため、遅延読み込みは、必要なときにのみキャッシュにデータを読み込むキャッシュ戦略です。

遅延読み込みの仕組み

Amazon ElastiCache メモリ内のキー / 値ストアで、アプリケーションとアプリケーションがアクセスするデータストア (データベース) 間にあります。アプリケーションがデータをリクエストする場合は、常に ElastiCache キャッシュに最初にリクエストを行います。データがキャッシュにあり最新である場合、ElastiCache はアプリケーションにデータを返します。データがキャッシュにない場合、またはキャッシュのデータの期限が切れている場合は、アプリケーションは、アプリケーションにデータを返すデータストアに対してデータをリクエストします。次に、アプリケーションは、ストアから受信したデータをキャッシュに書き込みます。したがって、次回リクエストされたときはより迅速に取得できます。

シナリオ 1: キャッシュヒット

データがキャッシュにあり期限切れでない場合

  1. アプリケーションは、キャッシュに対してデータをリクエストします。

  2. キャッシュはアプリケーションにデータを返します。

シナリオ 2: キャッシュミス

データがキャッシュにないか期限切の場合

  1. アプリケーションは、キャッシュに対してデータをリクエストします。

  2. キャッシュにはリクエストされたデータがないため、null を返します。

  3. アプリケーションはデータベースに対してデータをリクエストし、取得します。

  4. アプリケーションは、新しいデータでキャッシュを更新します。

次の図は、これらの両方のプロセスを示しています。

遅延読み込みの利点と欠点

遅延読み込みの利点

  • リクエストされたデータのみをキャッシュします。

    ほとんどのデータがリクエストされないため、遅延読み込みではデータでキャッシュがいっぱいになることを回避できます。

  • ノードの障害は致命的ではありません。

    ノードで障害が発生して新しい空のノードに置き換えられた場合、アプリケーションはレイテンシーが長くなっても機能し続けます。リクエストは新しいノードに対して行われるため、各キャッシュでエラーが発生すると、後続のリクエストがキャッシュからデータを取得できるように、データベースクエリが生じて、キャッシュへのデータのコピーが行われます。

遅延読み込みの欠点

  • キャッシュミスのペナルティがあります。

    1 回のキャッシュのミスで 3 回のトリップ、

    1. キャッシュに対する最初のデータリクエスト

    2. データベースへのデータクエリ

    3. キャッシュにデータを書き込む

    アプリケーションによるデータの取得に相当な遅延が発生する可能性があります。

  • 古いデータ。

    キャッシュミスがある場合にのみデータがキャッシュに書き込まれる場合は、データベスのデータが変更されるまでキャッシュが更新されないため、キャッシュのデータが古くなる可能性があります。この問題は、「書き込みスルー」および「TTL の追加」戦略で扱います。

遅延読み込みコード

次のコードは、遅延読み込みロジックの擬似コードの例です。

Copy
// ***************************************** // function that returns a customer's record. // Attempts to retrieve the record from the cache. // If it is retrieved, the record is returned to the application. // If the record is not retrieved from the cache, it is // retrieved from the database, // added to the cache, and // returned to the application // ***************************************** get_customer(customer_id) customer_record = cache.get(customer_id) if (customer_record == null) customer_record = db.query("SELECT * FROM Customers WHERE id == {0}", customer_id) cache.set(customer_id, customer_record) return customer_record

データを取得アプリケーションコードは次のとおりです:

Copy
customer_record = get_customer(12345)

書き込みスルー

書き込みスルー戦略では、データがデータベースに書き込まれると常にデータを追加するか、キャッシュのデータを更新します。

書き込みスルーの利点と欠点

書き込みスルーの利点

  • キャッシュのデータが古くなりません。

    キャッシュにデータベースにデータが書き込まれるたびにキャッシュのデータが更新されるため、キャッシュのデータが常に最新の状態になります。

  • 書き込みペナルティ対読み込みペナルティ

    1 回の書き込みで 2 回のトリップ:

    1. キャッシュへの書き込み

    2. データベースへの書き込み

    レイテンシーをプロセスに追加します。つまり、エンドユーザーは一般的に、データの取得時よりもデータの更新時のレイテンシーに対して寛容です。更新は作業量が大きく時間がかかるのが常です。

書き込みスルーの欠点

  • 欠落データ。

    新規ノードをスピンアップする場合は、ノード障害または拡張により、データの欠落が生じてデータベースにそれが追加されるか更新されるまで欠落した状態が継続します。これは、「遅延読み込み」を書き込みスルーと共に使用することで最小限にできます。

  • キャッシュの変動。

    ほとんどのデータは読み込まれないため、読まれることのないクラスターに大量のデータが存在することになります。これはリソース浪費です。「TTL の追加」で、無駄な領域を最小限に抑えることができます。

書き込みスルーコード

次のコードは、書き込みスルーロジックの擬似コードの例です。

Copy
// ***************************************** // function that saves a customer's record. // ***************************************** save_customer(customer_id, values) customer_record = db.query("UPDATE Customers WHERE id = {0}", customer_id, values) cache.set(customer_id, customer_record) return success

データを更新するアプリケーションコードは次のとおりです:

Copy
save_customer(12345,{"address":"123 Main"})

TTL の追加

遅延読み取りはデータが古くなる可能性がありますが、空ノードによる障害は発生しません。書き込みスルーでは常に新しいデータとなりますが、空ノードの障害が発生して、過剰なデータがキャッシュに入力される場合があります。それぞれの書き込みに有効期限 (TTL) の値を追加することで、それぞれの戦略の利点ができて、過剰なデータでキャッシュがいっぱいになる事態が避けられます。

TTL とは

有効期限 (TTL) は秒数を指定する整数値です (Redis では、キーの有効期間を秒またはミリ秒で指定できます)。アプリケーションが期限の切れたキーを読み込もうとすると、キーが見つからないものとして処理されます。これは、データベースにキーのクエリが行われて、キャッシュが更新されることを意味します。これは値が古くならないことを保証するわけではありませんが、データが古くなりすぎることを防ぎ、キャッシュの値がデータベースから時々更新されることを必要とします。

詳細については、「Redis setコマンド」または「Memcached setコマンド」を参照してください。

コード例

次のコードは、TTL のある書き込みスルーロジックの擬似コードの例です。

Copy
// ***************************************** // function that saves a customer's record. // The TTL value of 300 means that the record expires // 300 seconds (5 minutes) after the set command // and future reads will have to query the database. // ***************************************** save_customer(customer_id, values) customer_record = db.query("UPDATE Customers WHERE id = {0}", customer_id, values) cache.set(customer_id, customer_record, 300) return success

次のコードは、TTL のある遅延読み込みロジックの擬似コードの例です。

Copy
// ***************************************** // function that returns a customer's record. // Attempts to retrieve the record from the cache. // If it is retrieved, the record is returned to the application. // If the record is not retrieved from the cache, it is // retrieved from the database, // added to the cache, and // returned to the application. // The TTL value of 300 means that the record expires // 300 seconds (5 minutes) after the set command // and subsequent reads will have to query the database. // ***************************************** get_customer(customer_id) customer_record = cache.get(customer_id) if (customer_record != null) if (customer_record.TTL < 300) return customer_record // return the record and exit function // do this only if the record did not exist in the cache OR // the TTL was >= 300, i.e., the record in the cache had expired. customer_record = db.query("SELECT * FROM Customers WHERE id = {0}", customer_id) cache.set(customer_id, customer_record, 300) // update the cache return customer_record // return the newly retrieved record and exit function

アプリケーションコードは次のとおりです:

Copy
save_customer(12345,{"address":"123 Main"})
Copy
customer_record = get_customer(12345)

関連トピック