以前のバンドル サービス用の Memcache API

このページでは、App Engine memcache サービスの概要を説明します。高パフォーマンスでスケーラブルなウェブ アプリケーションでは多くの場合、一部のタスクの処理に、堅牢な永続ストレージに優先して(あるいはその代わりに)分散型のインメモリ データ キャッシュを使用します。App Engine にメモリ キャッシュ サービスが含まれているのはそのためです。memcache サービスの構成、モニタリング、使用方法については、memcache の使用をご覧ください。

メモリ キャッシュの用途

メモリ キャッシュの 1 つの用途は、一般的なデータストア クエリを高速化することです。多くのリクエストが、同じパラメータを使用して同じクエリを実行し、結果への変更をすぐにウェブサイトに表示する必要がない場合、アプリは memcache に結果をキャッシュに保存できます。後続のリクエストで、Memcache をチェックし、結果が存在しないか、または期限が切れている場合にのみ、データストア クエリを実行できます。セッション データ、ユーザー設定、およびウェブページへのクエリによって返されたその他のデータは、キャッシュに適した候補です。

Memcache は他の一時的な値にも便利です。ただし、memcache のみに値を保存し、他の永続ストレージを使用しないかどうかを検討する場合、値が突然使用できなくなったときに、アプリケーションが適切に動作するようにしてください。値はいつでも memcache で期限切れになる可能性があり、値に設定された有効期限よりも前に期限切れになる可能性もあります。たとえば、ユーザーのセッション データが突然なくなったために、セッションが誤動作する場合、そのデータはおそらく memcache に加えて、データストアにも保存する必要があると考えられます。

サービスレベル

App Engine は 2 つのレベルの memcache サービスをサポートしています。

  • 共有 memcache は App Engine アプリケーションの無料のデフォルトです。これは、ベストエフォート方式でキャッシュ容量を提供し、共有 memcache サービスを使用するすべての App Engine アプリケーションの総需要に基づきます。

  • 専用 memcache は、アプリケーションに排他的に割り当てられた固定キャッシュ容量を提供します。これはキャッシュ サイズの GB/時間に応じて課金されるため、課金を有効にする必要があります。キャッシュ サイズを管理することで、アプリの実行に対する予測可能性が向上し、よりコストがかかる長期保存用のストレージからの読み取りを減らすことができます。

どちらの memcache サービスレベルも同じ API を使用します。アプリケーション用に memcache サービスを構成するには、memcache の使用をご覧ください。

次の表に、2 つのクラスの memcache サービスの違いをまとめています。

機能 専用 Memcache 共有 Memcache
料金 $0.06/GB/時間 無料
容量
us-central
1~100 GB
asia-northeast1、europe-west、europe-west3、us-east1:
1~20 GB
その他のリージョン:
1~2 GB
保証された容量なし
パフォーマンス 最大 10,000 読み取りまたは 5,000 書き込み(排他的)/秒/GB(1 KB 未満のアイテム)。詳しくはキャッシュ統計をご覧ください。 保証なし
長期保存 × ×
SLA なし なし

専用 Memcache の料金は、15 分単位で課金されます。米ドル以外の通貨でお支払いの場合は、Cloud Platform SKU に表示されている通貨での料金が適用されます。

アプリでさらに多くの Memcache 容量が必要な場合は、Google のセールスチームまでお問い合わせください

制限

memcache サービスの使用には次の制限が適用されます。

  • キャッシュされるデータ値の最大サイズは 1 MB(10^6 バイト)です。
  • キーは 250 バイト以下にしてください。Python ランタイムでは、250 バイトより長い文字列のキーはハッシュされます(他のランタイムの動作は異なります)。
  • 「マルチ」バッチ処理では、任意の数の要素を使用できます。呼び出しの合計サイズとフェッチされるデータの合計サイズが 32 MB を超えないようにする必要があります。
  • Memcache キーには NULL バイトを格納できません。

推奨事項とベスト プラクティス

Memcache を使用する場合は、次のようにアプリケーションを設計することをおすすめします。

  • キャッシュに保存された値が常に利用できないケースに対処する。

    • Memcache は耐久性の高いストレージではありません。エビクション ポリシーに従って、キャッシュがいっぱいになると、キーが強制排除されます。キャッシュの構成の変更またはデータセンターのメンテナンス時にもキャッシュの一部またはすべてがフラッシュされる可能性があります。
    • Memcache が一時的に使用できなくなる場合があります。Memcache オペレーションは、キャッシュ構成の変更やデータセンターのメンテナンス イベントなど、さまざまな理由で失敗することがあります。アプリケーションは、エラーをエンドユーザーに通知せずに、失敗したオペレーションをキャッチするように設計されている必要があります。このガイダンスは Set オペレーションに特にあてはまります。
  • できるだけ API のバッチ機能を使用する

    • そうすることで、特に小さなアイテムにおいて、アプリのパフォーマンスと効率が向上します。
  • Memcache キースペース全体で負荷を分散する。

    • 不均一なトラフィックの量を 1 つまたは小さな Memcache アイテムのセットで表すことでアプリのスケーリングを妨げます。このガイダンスはオペレーション数/秒と帯域幅の両方にあてはまります。多くの場合、データの明示的なシャーディングによって、この問題を軽減できます。

      たとえば、頻繁に更新されるカウンタを複数のキーに分割し、合計が必要な場合にのみ読み取り、合算できます。同様に、読み取る必要がある 500 K のデータを複数のキーにまたがる各 HTTP リクエストに分割し、1 つのバッチ API 呼び出しを使用して、それらを読み取ることができます。(インスタンス メモリ内に値をキャッシュ保存した方がよい場合もあります)。専用 memcache の場合、単一キーのピークアクセス レートは、GB ごとの評価より 1、2 桁小さくなるはずです。

  • キャッシュから値を取得するために独自のキーを保持する。

    • Memcache にはキーを一覧表示するメソッドがありません。キャッシュの性質上、キャッシュを中断せずにキーを一覧表示することはできません。また、Python などの一部の言語、ハッシュ長のキー、元のキーはアプリケーションのみが認識できます。

キャッシュに保存されたデータの期限切れ

memcache には Key-Value ペアが格納されます。アイテムがキャッシュに書き込まれたり、キャッシュから取得されたりするため、メモリ内のペアはいつでも変更されます。

デフォルトで memcache に保存される値は、可能な限り長く保持されます。キャッシュに新しい値が追加され、キャッシュのメモリが不足すると、キャッシュから値が強制排除されます。メモリ圧縮のために値が強制排除されると、最も長く使用されていない値が最初に強制排除されます。

アプリでは、値が追加されたときからの相対秒数か、または将来の絶対 Unix エポック時間(1970 年 1 月 1 日午前 0 時からの秒数)のいずれかで、値が保存される有効期限を設定できます。値はこの時間までに強制排除されますが、他の理由でもっと早く強制排除されることがあります。既存のキーに格納されている値をインクリメントしても、その有効期限は更新されません。

まれに、メモリ圧縮以外の理由で、有効期限の前にキャッシュから値が消失することもあります。memcache はサーバーの障害に対する復元性がありますが、memcache の値はディスクに保存されないため、サービスの障害によって、値が使用できなくなることがあります。

一般に、アプリケーションでは、キャッシュに保存された値が常に使用できるものと期待するべきではありません。

API を使用するか、または Google Cloud コンソールの Memcache セクションでアプリケーションのキャッシュ全体を消去できます。

キャッシュ統計

アイテムサイズ別の 1 秒あたりのオペレーションの回数

専用 Memcache は 1 GB ごとの 1 秒あたりのオペレーションの回数で評価されます。ここでオペレーションとは、getset、または delete など、キャッシュ アイテムへの個別のアクセスとして定義されます。オペレーション数はだいたい次の表に従い、アイテムサイズによって異なります。これらの評価を超えると、API のレイテンシの増加またはエラーが発生する可能性があります。

次の表にキャッシュの GB あたりの継続的な排他的 get-hit または set オペレーションの最大数を示します。get-hit オペレーションは指定したキーで保存された値があることを検出し、その値を返す get 呼び出しです。

アイテムサイズ(KB) 最大 get-hit オペレーション数/秒 最大 set オペレーション数/秒
1 以下 10,000 5,000
100 2,000 1,000
512 500 250

数 GB のキャッシュが構成されているアプリは、理論上 GB 数と GB あたりのレートを乗算した数値として計算される合計オペレーション数を実現できます。たとえば、5 GB のキャッシュで構成されたアプリは 1 KB のアイテムで 50,000 memcache オペレーション数/秒に到達する可能性があります。このレベルを実現するには、Memcache キースペース全体で負荷を適切に分散する必要があります。

各 IO パターンで、上記の上限は読み取りまたは書き込みに対するものです。読み取りおよび書き込みを同時に行った場合、上限がスライドします。つまり、読み取りの実行が多くなると書き込みは減少し、書き込みが増加すると読み取りは減少します。1 GB のキャッシュあたりの 1 KB の値の読み書きを同時に行った場合の IOPS の上限の例を次に示します。

読み取り IOPS 書き込み IOPS
10,000 0
8,000 1,000
5,000 2,500
1,000 4,500
0 5,000

Memcache コンピューティング単位数(MCU)

memcache のスループットはアクセスしているアイテムのサイズおよびアイテムに対して行うオペレーションによって異なることがあります。コストとオペレーションはほぼ関連付けることができ、Memcache コンピューティング単位数(MCU)という単位を使用して、専用 memcache から予想できるトラフィック容量を見積もることができます。MCU は専用 memcache の 10,000 MCU/秒/GB を予想できるように定義されます。Google Cloud コンソールにアプリで現在使用している MCU の量が表示されます。

MCU はおおよその統計見積もりであり、線形単位ではありません。値の読み取りまたは書き込みをする各キャッシュ オペレーションは、値のサイズに依存した対応する MCU コストがかかります。set の MCU は値のサイズによって異なります。成功した get-hit オペレーションのコストの 2 倍になります。

値アイテムサイズ(KB) get-hit の MCU コスト set の MCU コスト
1 以下 1.0 2.0
2 1.3 2.6
10 1.7 3.4
100 5.0 10.0
512 20.0 40.0
1024 50.0 100.0

値を読み書きしないオペレーションには固定の MCU コストがかかります。

オペレーション MCU
get-miss 1.0
delete 2.0
increment 2.0
flush 100.0
stats 100.0

get-miss オペレーションは指定したキーで値が保存されていないことを検出する get です。

compare と set

compare と set は、競合状態を回避しながら、同時に処理される複数のリクエストで、同じ memcache キーの値をアトミックに更新できるようにする機能です。

compare と set の主な論理コンポーネント

他の同時書き込みリクエストを受け取る可能性がある Memcache キーの値を更新する場合、compare と set をサポートするメソッドにより使用される特定の状態情報を保存する Client オブジェクトを使用する必要があります。Memcache 関数 get()set() は、ステートレスなので使用できません。Client クラス自体はスレッドセーフではないので、複数のスレッドで同じ Client オブジェクトを使用しないでください。

キーを取得するときは、compare と set をサポートする memcache Client メソッドを使用する必要があります。つまり、for_cas パラメータを True に設定した gets() または get_multi() です。

キーを更新するときは、compare と set をサポートする memcache Client メソッドを使用する必要があります。つまり、cas() または cas_multi() です。

もう 1 つの主な論理コンポーネントは、App Engine memcache サービスとその compare と set に関する動作です。App Engine memcache サービス自体は、アトミックに動作します。つまり、同じ app id に対する 2 つの同時リクエストが memcache を使用する場合、同じ memcache サービス インスタンスに対してリクエストが行われますが、memcache サービスは十分な内部ロック機能を持っているので、同じキーに対する同時リクエストが適切にシリアル化されます。これは特に、同じキーに対する 2 つの cas() リクエストが実際には並行して実行されないことを意味します。このサービスは、2 番目のリクエストの処理を開始する前に、最初に入ったリクエスト(つまり、値とタイムスタンプの更新)が完了するまで処理します。

Python で compare と set を使用する方法については、同時書き込みの処理を参照してください。

次のステップ