Amazon Web Services ブログ

Amazon CloudFront でのタグベースによるキャッシュ削除

この記事では、Lambda@Edge, Amazon DynamoDB, AWS Lambda, および AWS StepFunctoins を使用して Amazon CloudFront のタグベースでのキャッシュ削除を実装する方法について説明します。また、タグベースのキャッシュ削除をデプロイしてテストするのに役立つリファレンスアーキテクチャとサンプルコードを提供します。

まず、ページをまとめてタグ付けすると便利なユースケースをいくつか紹介します。

  • ブランドページ – 直販企業(D2C)は、お客様や検索エンジンのボットが発見し易いように、ブランドや製品に関する情報をウェブサイトやモバイルアプリケーションにまとめています。一般的に、ブランドページ、製品リストページ、製品仕様ページと階層的にまとめています。これらは、カテゴリーページやあらかじめ用意された検索語ページなどの補助的なページに結び付けられることもあります。これらはすべてつながっており、ブランドや製品仕様の更新に影響されます。例えば、自動車メーカーが、ブランド、モデルリスト、詳細仕様のページを、ブランドと製品コードを使ってグループ化したい場合があります。
  • ニュースポータル – ニュース速報やスポーツイベント、記者発表などのイベントをライブ中継する Web サイトでは、写真、ビデオ、スコアティッカー、スコアボード、統計情報などの豊富なマルチメディアコンテンツを含むページを頻繁に更新する必要があります。イベントに関連するすべてのアセットを無効にすることで、視聴者は新しいコンテンツにいち早くアクセスすることができます。
  • 複数のレンディションを持つ画像サイト – 画像などのリッチメディアコンテンツは、デバイスの特性に基づいて最適化されるため、同じコンテンツが複数表示されることになります。例えば、レスポンシブデザインでは、画像はサムネイルと異なるサイズで表示されることがあります。元の画像を更新するとそのすべての表示が更新されるはずですが、それらがグループ化されていれば、より簡単になります。

これらすべてのシナリオで、1 つ以上のタグに基づいてコンテンツをグループ化し、個々のファイルではなくタグに基づいてキャッシュを削除することができます。キャッシュ削除ワークフローにインテリジェンスを追加することで、コンテンツの更新時に複数のファイルを更新する必要がある際のオペレーション効率を向上させることができます。

CloudFront には、ビューワーがアプリケーションのバックエンドを操作するときに (リクエストまたはレスポンスの) 情報を処理する 4 つのイベントトリガーが用意されています。この機能といくつかの AWS サービスを利用して、タグベースのキャッシュ削除ワークフローを実装します。CloudFront イベントトリガーの詳細については ここ を参照してください。

ソリューションの概要

このソリューションは、2 つのコンポーネントで構成されています:

  1. タグの取り込みワークフロー:タグとコンテンツのマッピングの取り込みと、永続化を担当します。各コンテンツURLは、あらかじめ定義されたレスポンスヘッダーに1つ以上のタグを指定することができます。
  2. タグベースのキャッシュ削除ワークフロー:1 つまたは複数のタグに基づくキャッシュ削除を担当します。このシステムは、タグとコンテンツのマッピングを読み取り、重複を排除し、CloudFront の 無効化のクォータ 内に収まるように制御された方法でキャッシュ削除を実行する役割を担っています。

それでは、各コンポーネントの実装の詳細を見ていきましょう。

タグの取り込みワークフロー

図1: タグの取り込みワークフロー

図1: タグの取り込みワークフロー

タグの取り込みワークフローの一環として、アプリケーションのバックエンドから来るレスポンスヘッダーを捕まえるためのリスナーを設定します。アプリケーションは、事前に定義されたレスポンスヘッダーに 1 つ以上のタグを送信します。この追加メタデータは、URL と 1 つ以上のタグ間のマッピングを維持するために使用されます。

Chrome デベロッパーツールから見たレスポンスヘッダーの例を以下に示します。’Edge-Cache-Tag ’ は、3 つのタグレベルの情報を保持し、カンマで区切られていることに注意してください。検索する特定のレスポンスヘッダーをカスタマイズしたり、タグをカンマまたはスペースで区切ったりできます。これらはオリジンレスポンスのヘッダーであるため、Lambda@Edge 関数は処理後にこれらのヘッダーを削除することに注意してください。

図2: キャッシュタグを含むオリジンレスポンスヘッダーの例

図2: キャッシュタグを含むオリジンレスポンスヘッダーの例

タグ取り込みワークフロー :

  1. Lambda@Edge 関数を、ビヘイビアの ’Origin-Response (オリジンレスポンス)’ に関連付けます。この関数は、キャッシュミス時と、CloudFront がオリジンからレスポンスを受信する直前にのみ実行されます。そのため、冗長な情報でダウンストリームのタグ取り込みシステムに負荷をかけすぎることなく、タグとコンテンツ間のマッピングをキャプチャできる理想的なイベントトリガーになります。
  2. Amazon Simple Notification Service (Amazon SNS) トピックは、Lambda@Edge が実行される Regional Edge Cache (REC) 毎に作成されます。これは、タグと関連する URL を取得し、永続化するための情報を中継する際の待ち時間を最小化するために行われます。
  3. 選択した AWS リージョンにデプロイされた Amazon Simple Queue Service (Amazon SQS) は、前述の各リージョンにある Amazon SNS トピックをサブスクライブしています。これにより、異なるリージョンからタグ情報を中央のロケーションに集めることができます。
  4. スケジュールで起動するリージョンのLambda関数:Amazon SQSキューからメッセージを取得し、DynamoDB テーブルに保存します。

なお、Lambda@Edge 関数は、リクエストされた URL に対してオリジンからエラーが返された場合でも実行されることに注意してください。HTTP 200 OK のみをフィルタリングして動作させたい場合は、HTTP ステータスコードのソースコードに追加のチェックを組み込むことができます。

タグベースのキャッシュ削除ワークフロー

図 3: タグベースのキャッシュ削除ワークフロー

図 3: タグベースのキャッシュ削除ワークフロー

タグベースのキャッシュ削除ワークフローを起動するために特権ユーザが下記のアクションを行います。

  1. CloudFront ディストリビューション ID からキャッシュ削除する 1 つ以上のタグを含むJSONペイロードを送信します。
  2. Step Functionsワークフローは、最初に DynamoDBテーブルからマッピングされたURLを取得し、パージキューにポストします。
  3. スケジュールベースの Purge Lambda 関数は、CloudFront に送信されたアクティブなキャッシュ削除の数を監視し、パージキューにメッセージを送ります。この Lambda 関数は、キャッシュ削除 API で許可された制限内に収まるように、CloudFront のキャッシュ削除 API に新しい URL を送ります。

リファレンスソリューション

リファレンスソリューションの GitHubリポジトリ はこちらです。

前提条件
リファレンス・ソリューションを展開するために下記が必要です。

  • あらかじめ定義されたレスポンスヘッダー (デフォルトは ‘Edge-Cache-Tag’) でタグを送信するバックエンドアプリケーション(オリジン)
  • AWS Cloud Development Kit (AWS CDK) を使用してリソースを作成する権限のある AWS クレデンシャル
  • テストするための CloudFrontディストリビューション

ソリューションのテスト

リファレンスソリューションの導入とテストには、主に次の 5 つのステップが必要です。

  1. GitHubリポジトリ の指示に従いソリューションをデプロイします。
  2. Lambda@Edge のオリジンレスポンス関数を CloudFront のディストリビューションに関連付けてテストします。
  3. 新しく作成された DynamoDB テーブルにアクセスし、タグが取り込まれていることを確認します。
  4. Step Functions ワークフローを使用して、タグを指定したキャッシュ削除リクエストを送信します。
  5. CloudFront コンソールからタグ付き URL のキャッシュが削除されたことを確認します。

ステップ 1 : GitHub リポジトリに従ってソリューションをデプロイする

プロジェクトのビルド方法に関する説明とともに、GitHub リポジトリ からリファレンスソリューションを見つけることができます。ソリューションをデプロイするために設定できるパラメータについては、’Steps to build’ セクションを参照してください。このソリューションでは、オリジンレスポンスからタグを受信するための Lambda@Edge 関数をデプロイします。ソリューションは一度デプロイするだけでよく、オリジンレスポンストリガーを使用して Lambda@Edge 関数をさまざまな CloudFront のビヘイビアに関連付けることができます。env.sh ファイルのキャッシュタグヘッダーやタグ区切り文字など、ソリューションのパラメーターを指定できます。デフォルトでは、ソリューションでは “Edge-Cache-Tag” レスポンスヘッダーを使用してオリジンからキャッシュタグを受け取ります。複数のタグをカンマで区切って指定することが出来ます。

オプションとして、前述のパラメーターに加えて、DynamoDB のテーブルに古いレコードが蓄積されるのを防ぐために、各タグに Time-To-Live (TTL) を指定することができます。“TAG_TTL_NAME” は、TTL を含むオリジンレスポンスヘッダーを秒単位で指定します。デフォルトのヘッダー名は “tag-ttl “で、オリジンがレスポンスを返す際にヘッダー値を指定する必要があります。env.sh ファイルの “TAG_TTL_DEFINED_BY ” は、TTL 計算においてどのレスポンスヘッダーを優先するかを指定します。例えば、”TAG_TTL_DEFINED_BY=tag-ttl” を指定した場合、”tag-ttl” ヘッダーに設定された値が最初に優先され、次に ‘Cache-Control’ ヘッダーに設定されている値が優先され、逆も同様です。TTLを完全に無効にしたい場合は、”TAG_TTL_DEFINED_BY” に空の値を指定してください。

Lambda@Edge 関数は us-east-1 リージョンにデプロイされ、他のアーティファクトは複数のリージョンにデプロイされることに注意してください。DynamoDB テーブル と Step Functions ワークフロー は、設定ファイルのプライマリーリージョンとして指定されたリージョンにデプロイされます。リージョナルスタックがデプロイされる他のリージョンは us-east-2 , us-west-2, ap-south-1, ap-northeast-1, ap-northeast-2, ap-southeast-1, ap-southeast-2, eu-central-1, eu-west-1, eu-west-2, sa-east-1 になります。

Amazon CloudFront のリージョン別エッジキャッシュの詳細については、こちらを参照してください。

ステップ 2 : Lambda@Edge オリジンレスポンス関数を CloudFront ディストリビューションに関連付けてテストする

  1. デプロイが完了すると、AWS CDK はタグを取り込むための Lambda@Edge 関数の ARN を出力します。ARN をコピーして、関数を CloudFront のビヘイビアに関連付けます。

    図 4: タグ埋め込み用 Lambda@Edge 関数のARNの出力

    図 4: タグ埋め込み用 Lambda@Edge 関数のARNの出力

  2. Amazon CloudFront コンソールに移動し、オリジンレスポンスでタグを返すオリジンを含む CloudFront ディストリビューションを選択または作成します。“Behaviors (ビヘイビア)” タブで、タグ取り込み Lambda@Edge 関数に関連付けるキャッシュビヘイビアを選択し、“Edit (編集)” を選択します。

    図 5: タグベースのキャッシュ削除のためのビヘイビアを選択

    図 5: タグベースのキャッシュ削除のためのビヘイビアを選択

  3. ビヘイビア設定で、“Function associations (関数の関連付け)” セクションまでスクロールします。オリジンレスポンストリガーにLambda@Edge を選択し、AWS CDK の出力にある Function ARN を貼り付け、Save changes (変更を保存)します。

    図6: タグ取り込み Lambda@Edge 関数の関連付け

    図6: タグ取り込み Lambda@Edge 関数の関連付け

  4. テストする前にキャッシュを削除します。ディストリビューションドメイン名を確認し、CloudFront からコンテンツをダウンロードして、キャッシュにデータを入力し、オリジンからタグを取り込みます。“x-cache” レスポンスヘッダーの値は、最初のリクエストでは “Miss from cloudfront”、それ以降のリクエストでは “Hit from cloudfront” でなければなりません。

    図 7: CloudFront レスポンスヘッダーのキャッシュ(x-cache)を確認する

    図 7: CloudFront レスポンスヘッダーのキャッシュ(x-cache)を確認する

ステップ 3 : 新しく作成した DynamoDB テーブルに移動して、タグの取り込みを確認する

  1. ソリューションをデプロイするために選択したリージョンの DynamoDB コンソールに移動します。“ Table (テーブル)” から ” Explore items (項目を探索)“ に移動すると、” TagPrimaryStack-{distributionID}“ という名前で作成された新しいテーブルが見つかります。{DistributionId} は、前のステップで使用した CloudFront ディストリビューションのディストリビューション ID です。CloudFront 継続的デプロイ機能を使用してステージングディストリビューションでテストする場合は、ステップ 2 で説明されているようにステージングディストリビューションも設定する必要があることに注意してください。これにより、ステージング CloudFront ディストリビューション ID を使用して別の DynamoDB テーブルが作成されます。
  2. CloudFront にキャッシュされたコンテンツのキャッシュタグとタグ付き URI を含むエントリがテーブルに入力されていることを確認できます。次の図の例は、さまざまな車の年式、モデル、色をタグ付けした例を示しています。

    図 8: DynamoDBに登録された tag/URL を確認

    図 8: DynamoDBに登録された tag/URL を確認

  3. テーブルエントリから、次のステップでキャッシュ削除に使用するタグを選択し、そのタグに関連付けられた URI を書き留めます。

ステップ 4 : Step Functions ワークフローを使用してタグによるキャッシュ削除リクエストを送信する

  1. ソリューションをデプロイするために選択したリージョンの Step Functions コンソールに移動して、ステートマシンのリストからステートマシン “TagPrimarystackPurgeWorkflow” を探します。ステートマシンを選択し、“View details (詳細を表示)” を選択します。
  2. 詳細画面の “ Executions (実行) “ タブで ” Start execution (実行を開始) “ を選択し、タグによるキャッシュ削除を作成します。
  3. ”Start execution (実行を開始)“ 画面で、CloudFront ディストリビューション ID とキャッシュ削除に使用したいタグを指定した後、”Input (入力)“ セクションに次の文字列を入力します。次に、”Start execution (実行を開始)“ を選択します。複数のタグは OR ステートメントのように個別に評価されることに注意してください。
    {
    "distributionId": "CLOUDFRONT_DISTRIBUTION_ID",
    "tags": ["TAG1","TAG2"]
    }
  4. この例では “ year-2021 ” と “ model-suv ” というタグを使用してキャッシュを削除をします。

    図 9: タグベースによるキャッシュ削除の実行例

    図 9: タグベースによるキャッシュ削除の実行例

  5. 実行の詳細タブで、“Execution Status (実行ステータス)” が “Succeeded (成功)” になっていることを確認します。

    図 10: 実行ステータスを確認

    図 10: 実行ステータスを確認

ステップ 5 : CloudFront コンソールからタグ付き URL のキャッシュ削除を確認する

  1. CloudFront コンソールに移動し、使用している CloudFront ディストリビューションを選択します。次に、“Invalidations (キャッシュ削除)” タブに移動して、キャッシュ削除のリストを表示します。
  2. キャッシュ削除 ID のリストから、送信されたキャッシュ削除リクエストを見つけて選択し、“View details (詳細を表示)” を選択します。
  3. “Invalidation details (キャッシュ削除の詳細)” 画面で、ステータスが “Completed (完了済み)” であることと、“Object paths (オブジェクトパス)” に、キャッシュ削除リクエストで送信したタグ値でタグ付けされたURIが含まれていることを確認します。

    図11: タグ付き URI のキャッシュ削除を確認

ソリューションの実行にかかる見積もり費用と、異なるAWSサービスコンポーネントによる内訳は、リポジトリの ’Pricing Calculation’ セクションで確認できます。

トラブルシューティングについては、リポジトリの ‘Troubleshooting’ セクションを参照してください。

クリーンアップ

テストが完了したら、“cdk” ディレクトリで destroy.sh スクリプトを実行することで、ソリューションを削除し AWS CDK プロジェクトによって作成されたリソースに関連するコストを回避できます。スクリプトを実行する前に、Lambda@Edge 関数がすべての CloudFront ビヘイビアと関連付けられていないこと、および AWS CDK によって作成された CloudFormation スタックの削除保護が無効になっていることを確認してください。AWS CDK プロジェクトが破棄されたら、DynamoDB テーブルも手動で削除する必要があります。このスクリプトでは、他の AWS CDK プロジェクトに使用できる AWS CDK ブートストラップ CloudFormation スタックと Amazon Simple Storage Service (Amazon S3) バケットは削除されません。スタックとバケットを使用する予定がない場合は、手動で削除することが出来ます。

まとめ

今回のまとめとして、タグベースのキャッシュ削除を使用できるシナリオを学んだ後、AWS Lambda, Lambda@Edge, Amazon DynamoDB, AWS Step Functions, Amazon Simple Notification Service(SNS), Amazon Simple Queue Service(SQS) などのサービスを使用して Amazon CloudFront のタグベースのキャッシュ削除ソリューションを実装する方法を説明しました。このソリューションでは、1つまたは複数のタグに基づいてキャッシュされたコンテンツをグループ化し、パスやファイルではなくタグに基づいてキャッシュを削除することができます。キャッシュ削除ワークフローにさらなるインテリジェンスを加えることで、コンテンツの更新時に複数のキャッシュファイルをリフレッシュする必要があるユースケースにおいて、運用効率を向上させることができます。

この記事は、Tag-based invalidation in Amazon CloudFront を翻訳したものです。
このブログの翻訳は Solutions Architect の深井 宣之が担当しました。