Amazon Web Services ブログ

CloudFront Functions の導入 – 任意の規模において低レイテンシーでコードをエッジで実行

Amazon CloudFront を使用すると、データ、動画、アプリケーション、API を低レイテンシーと高速転送速度で世界中の顧客に安全に配信できます。カスタマイズされたエクスペリエンスを可能な限り最小のレイテンシーで提供するために、今日の多くのアプリケーションはエッジで何らかの形式のロジックを実行します。エッジでロジックを適用するユースケースは、主に 2 つのカテゴリに分類できます。

  • 最初のカテゴリは、オブジェクトがキャッシュにないときに実行される複雑な計算負荷の高いオペレーションです。私たちは、広範で複雑なカスタマイズを実装するための完全にプログラミング可能なサーバーレスエッジコンピューティング環境を提供するために 2017 年に Lambda@Edge立ち上げました。Lambda@Edge 関数は、リージョンのエッジキャッシュで実行されます (通常は、クライアントがアクセスする CloudFront エッジロケーションに最も近い AWS リージョン内にあります)。たとえば、動画やオーディオをストリーミングする場合、Lambda@Edge を使用して適切なセグメントをすばやく作成して提供することで、オリジンのスケーラビリティの必要性を減らすことができます。もう 1 つの一般的なユースケースは、Lambda@Edge と Amazon DynamoDB を使用して、短縮されたユーザーフレンドリーな URL を完全な URL ランディングページに変換することです。
  • ユースケースの 2 番目のカテゴリは、非常に短命の関数で実行できるシンプルな HTTP(S) リクエスト/レスポンス操作です。このユースケースでは、パフォーマンス、スケール、費用対効果を備え、各リクエストで操作を実行できる柔軟なプログラミングエクスペリエンスが必要です。

この 2 番目のユースケースを支援するために、218 以上の CloudFront エッジロケーションで軽量の JavaScript コードを Lambda@Edge の 1/6 のコストで実行できる新しいサーバーレススクリプトプラットフォームである CloudFront Functions の提供が開始されました。

アーキテクチャ図。

CloudFront Functions は、次のようなウェブリクエストの軽量な処理に最適です。

  • キャッシュキーの操作と正規化: HTTP リクエスト属性 (URL、ヘッダー、クッキー、クエリ文字列など) を変換して、キャッシュキーを作成します。キャッシュキーは、キャッシュ内のオブジェクトの一意の識別子で、オブジェクトが既にキャッシュされているかどうかを判断するために使用されます。たとえば、エンドユーザーのデバイスタイプを含むヘッダーに基づいてキャッシュし、モバイルユーザーとデスクトップユーザー用に 2 つの異なるバージョンのコンテンツを作成できます。リクエスト属性を変換することで、複数のリクエストを 1 つのキャッシュキーエントリに正規化し、キャッシュヒット率を大幅に向上させることもできます。
  • URL の書き換えとリダイレクト: リクエストを別の URL にリダイレクトするレスポンスを生成します。たとえば、認証されていないユーザーを制限付きページからログインフォームにリダイレクトできます。URL の書き換えは、A/B テストにも使用できます。
  • HTTP ヘッダーの操作: リクエスト/レスポンスヘッダーを表示、追加、変更、または削除します。たとえば、 HTTP Strict Transport Security (HSTS) ヘッダーをレスポンスに追加するか、クライアント IP アドレスを新しい HTTP ヘッダーにコピーして、リクエストとともにオリジンに転送できます。
  • アクセス承認: リクエストを許可/拒否するために、HMAC トークンや JSON ウェブトークン (JWT) などのユーザー生成トークンを作成して検証することにより、CloudFront 経由で配信されるコンテンツのアクセスコントロールと承認を実装します。

最新のアプリケーションに必要なパフォーマンスとスケールを実現するために、CloudFront Functions では、AWS Lambda と Lambda@Edge で使用されている仮想マシン (VM) ベースの分離ではなく、新しいプロセスベースの分離モデルを使用します。そのためには、ネットワークやファイルシステムのアクセスの回避などの制限を適用する必要がありました。また、関数は 1 ミリ秒未満で実行されます。このようにして、毎秒数百万のリクエストを処理しながら、すべての関数実行で優れたパフォーマンスを提供することが可能です。関数によるコンテンツ配信ネットワーク (CDN) の全体的なパフォーマンスへの影響は、ほとんどありません。

Lambda@Edge と同様に、CloudFront Functions は、CloudFront によって生成されたイベントに応答してコードを実行します。具体的には、CloudFront Functions は、CloudFront がビューアからのリクエスト (ビューアリクエスト) を受信した後、および CloudFront がビューアへのレスポンス (ビューアレスポンス) を転送する前にトリガーできます。

CloudFront がオリジンへのリクエスト (オリジンリクエスト) を転送する前、および CloudFront がオリジンからのレスポンス (オリジンレスポンス) を受信した後に Lambda@Edge をトリガーすることもできます。コンテンツを操作するタイミング (キャッシュの前または後) に応じて、CloudFront Functions と Lambda@Edge を一緒に使用することができます。

アーキテクチャ図。

ネットワークアクセスや長い実行時間など、CloudFront Functionsでは利用できない Lambda@Edge の機能が必要な場合は、CloudFront によってコンテンツがキャッシュされる前と後に Lambda@Edge を使用できます。

アーキテクチャ図。

CloudFront Functions と Lambda@Edge の違いを理解するために、ここでは簡単な比較を示します。

CloudFront Functions Lambda@Edge
ランタイムサポート JavaScript
(ECMAScript 5.1準拠)
Node.js、Python
実行場所 218 以上の CloudFront
エッジロケーション
13 の CloudFront
リージョンのエッジキャッシュ
サポートされる CloudFront トリガー ビューアリクエスト
ビューアレスポンス
ビューアリクエスト
ビューアレスポンス
オリジンリクエスト
オリジンレスポンス
最大実行時間 1 ミリ秒未満 5 秒 (ビューアトリガー)
30 秒 (オリジントリガー)
最大メモリ 2 MB 128 MB (ビューアトリガー)
10 GB (オリジントリガー)
合計パッケージサイズ 10 KB 1 MB (ビューアトリガー)
50 MB (オリジントリガー)
ネットワークアクセス なし あり
ファイルシステムアクセス なし あり
リクエスト本文へのアクセス なし あり
料金 無料利用枠あり。
リクエストごとに課金。
無料利用枠なし。リクエストと
関数の実行時間ごとに課金。

以降のセクションでは、どのように機能するかを見てみましょう。

コンソールから CloudFront Functions を使用する
ここでは、ビューアの国に応じて、自分のウェブサイトのコンテンツをカスタマイズしようと思います。そのために、S3 バケットをオリジンとして使用して作成した CloudFront ディストリビューションを使用します。次に、(ビューアの国を表す 2 文字の国コードを含む) CloudFront-Viewer-Country ヘッダーをキャッシュキーに含めるキャッシュポリシーを作成します。CloudFront で生成されたヘッダーは、オリジンポリシーまたはキャッシュキーポリシーに含まれている場合にのみ CloudFront Functions で (CloudFront の地理的位置情報デバイス検出ヘッダーと同様に) 認識されます。

CloudFront コンソールの左側のバーで [Functions] (関数) を選択し、[Create function] (関数を作成) を選択します。関数に名前を付けて [Continue] (続行) をクリックします。

コンソールのスクリーンショット。

ここから、次の手順で機能のライフサイクルを示します。

  1. コードを指定して関数を構築します。
  2. サンプルペイロードで関数をテストします。
  3. 開発ステージからライブステージに関数を公開します。
  4. 関数を 1 つ以上の CloudFront ディストリビューションに関連付けます

コンソールのスクリーンショット。

1.[Build] (ビルド) タブでは、各関数の 2 つのステージ (テスト用の開発ステージと 1 つ以上の CloudFront ディストリビューションで使用できるライブステージ) にアクセスできます。開発段階を選択し、関数のコードを入力して保存します。

function handler(event) {
  var request = event.request;
  var supported_countries = ['de', 'it', 'fr'];
  if (request.uri.substr(3,1) != '/') {
    var headers = request.headers;
    var newUri;
    if (headers['cloudfront-viewer-country']) {
      var countryCode = headers['cloudfront-viewer-country'].value.toLowerCase();
      if (supported_countries.includes(countryCode)) {
        newUri = '/' + countryCode + request.uri;
      }
    }
    if (newUri === undefined) {
      var defaultCountryCode = 'en';
      newUri = '/' + defaultCountryCode + request.uri;
    }
    var response = {
      statusCode: 302,
      statusDescription: 'Found',
      headers: {
        "location": { "value": newUri }
      }
    }
    return response;
  }
  return request;
}

この関数は、CloudFront によって設定された CloudFront-Viewer-Country の内容を調べます。サポートされている国が含まれていて、国プレフィックス URL にまだ含まれていない場合は、URL パスの先頭に国が追加されます。それ以外の場合、リクエストは変更なしで処理されます。

2.[Test] (テスト) タブで、イベントタイプ (ビューアリクエスト)、ステージ (現時点では開発)、サンプルイベントを選択します。

コンソールのスクリーンショット。

HTTP メソッドを選択し、URL のパス、および使用するクライアント IP (オプション) を編集することで、Input イベントをカスタマイズできます。カスタムヘッダー、クッキー、またはクエリ文字列を追加することもできます。この場合、すべてデフォルト値のままにして、FR (フランス) の値で CloudFront-Viewer-Country ヘッダーを追加します。ビジュアルエディターを使用する代わりに、関数に渡される JSON ペイロードを編集して入力イベントをカスタマイズすることもできます (オプション)。

コンソールのスクリーンショット。

[Test] (テスト) ボタンをクリックして、[Output] (出力) を確認します。予期した通り、リクエストがリダイレクトされます (HTTP ステータスコード 302)。レスポンスヘッダーでは、リクエストがリダイレクトされる場所 (location) は /fr/ で始まるので、フランスのビューアにカスタムコンテンツが提供されることを確認できます。テストで予期しない結果が生じた場合は、[Function Logs] (関数ログ) を確認できます。コードで console.log() を使用して、追加のデバッグ情報を追加することもできます。

コンソールのスクリーンショット。

HTTPステータスのすぐ上の [Output] には、この実行の [Compute utilization] (コンピューティング使用率) が表示されます 。コンピューティング使用率は、関数の実行にかかった時間の長さを最大許容時間に対するパーセンテージで示す 0 ~ 100 の数値です。この場合、21 というコンピューティング使用率は、関数が最大許容時間の 21% で完了したことを意味します。

3.URL とヘッダーの別の構成を使用してさらにテストを実行し、[Publish] (公開) タブに移動して、関数を開発ステージからライブステージにコピーします。これで、関数を既存のディストリビューションに関連付ける準備ができました。

コンソールのスクリーンショット。

4.[Associate] (関連付け) タブで、[Distribution] (ディストリビューション)、[Event type] (イベントタイプ) ([Viewer Request] または [Viewer Response])、[Cache behavior] (キャッシュの動作) を選択します (このディストリビューションのキャッシュの動作はデフォルトの [Defaultデフォルト (*)] だけです)。[Add association] (関連付けの追加) をクリックし、ダイアログで確定します。

コンソールのスクリーンショット。

[Associate] タブの下部に関数の関連付けが表示されます。

コンソールのスクリーンショット。

この設定を 2 つの異なる場所からテストするために、2 つの Amazon Elastic Compute Cloud (EC2) インスタンスを起動します。1 つは米国東部 (バージニア北部) リージョンのインスタンスで、もう 1 つは欧州 (パリ) リージョンのインスタンスです。SSH を使用して接続し、cURL を使用して、CloudFrontディストリビューションからオブジェクトを取得します 。先に、ディストリビューションのオリジンとして使用される 2 つのオブジェクトを S3 バケットにアップロードしておきました。1 つは、フランスに拠点を置くビューア向けのものとして fr/ プレフィックスを使用し、サポートされていない国のビューアのためには、en/ プレフィックスを使用しました。

AWS Command Line Interface (CLI) を使用して 2 つのオブジェクトをリストします。

$ aws s3 ls --recursive s3://BUCKET
2021-04-01 13:54:20         13 en/doc.txt
2021-04-01 13:54:20          8 fr/doc.txt

米国東部 (バージニア北部) リージョンの EC2 インスタンスで、次のコマンドを実行してオブジェクトをダウンロードします。

[us-east-1]$ curl -L https://d2wj2l15gt32vo.cloudfront.net/doc.txt 
Good morning

次に、同じコマンドを欧州 (パリ) リージョンで実行します。

[eu-west-3]$ curl -L https://d2wj2l15gt32vo.cloudfront.net/doc.txt
Bonjour

予期した通り、同じ URL から異なる結果を得ることができました。ここでは -L オプションを使用しているので、cURL は、それが受信したリダイレクトに従います。このようにして、各コマンドは 2 つの HTTP リクエストを実行しています。最初のリクエストは CloudFront Functions から HTTP リダイレクトを受け取り、2 番目のリクエストはリダイレクトに従います。2 番目のリクエストの URLにはカスタムパス (/en/ または /fr/) が含まれるので変更されません。

リダイレクトの実際の場所とすべての HTTP レスポンスヘッダーを表示するには、-i オプションを指定して cURL を使用します。米国で実行されている EC2 インスタンスのレスポンスヘッダーを次に示します。関数は、バージニア州のエッジロケーションで実行されています。

[us-east-1]$ curl -i https://d2wj2l15gt32vo.cloudfront.net/doc.txt 
HTTP/2 302 
server: CloudFront
date: Thu, 01 Apr 2021 14:39:31 GMT
content-length: 0
location: /en/doc.txt
x-cache: FunctionGeneratedResponse from cloudfront
via: 1.1 cb0868a0a661911b98247aaff77bc898.cloudfront.net (CloudFront)
x-amz-cf-pop: IAD50-C2
x-amz-cf-id: TuaLKKg3YvLKN85fzd2qfcx9jOlfMQrWazpOVmN7NgfmmcXc1wzjmA==

次に、フランスで実行されている EC2 インスタンスのレスポンスヘッダーを示します。この関数はパリ近郊のエッジロケーションで実行されます。

[eu-west-3]$ curl -i https://d2wj2l15gt32vo.cloudfront.net/doc.txt
HTTP/2 302 
server: CloudFront
date: Thu, 01 Apr 2021 14:39:26 GMT
content-length: 0
location: /fr/doc.txt
x-cache: FunctionGeneratedResponse from cloudfront
via: 1.1 6fa25eadb94abd73b5efc56a89b2d829.cloudfront.net (CloudFront)
x-amz-cf-pop: CDG53-C1
x-amz-cf-id: jzWcbccJiTDRj22TGwsn_

利用可能なリージョンと料金
CloudFront Functions は現在利用可能で、新規および既存のディストリビューションで使用できます。CloudFront Functions は、AWS マネジメントコンソールAWS Command Line Interface (CLI)AWS SDKAWS CloudFormation で使用できます。CloudFront Functions では、呼び出しの回数に基づいて課金されます。CloudFront Functions は、AWS の無料利用枠を利用して使用を開始できます。詳細については、CloudFront 料金ページを参照してください。

CloudFront Functions の使用を今すぐ開始して、アプリケーションのエッジにカスタムロジックを追加してください。

Danilo