エッジ機能
概要
エッジ関数は、CloudFront を使用してエッジにカスタムロジックを追加するための強力な開発者ツールです。エッジ機能により、開発者は待ち時間を短縮しながらウェブアプリケーションを充実させ、完全に分散されたアプリケーションを構築できます。エッジ関数は次の用途に使用できます。
- 高度な HTTP ロジックの実装。CloudFront には、HTTP から HTTPS へのリダイレクト、リクエストパスに基づくさまざまなオリジンへのルーティングなどのネイティブなルールが用意されています。エッジ関数を使用すると、CloudFront のネイティブ機能を超えて、キャッシュキーの正規化、URL の書き換え、HTTP CRUD 操作などの高度な HTTP ロジックを実装できます。
- アプリケーションレイテンシーの短縮。アプリケーションロジックの中には、オリジンからエッジにオフロードしてキャッシュの利点を生かしたり (A/B テストなど)、ユーザーの近くで実行したり (HTTP リダイレクト、URL 短縮、HTML レンダリングなど) したりできるものがあります。マイクロサービスやマイクロフロントアーキテクチャでは、エッジ機能を使用して共通のロジック (承認や認証など) を各コンポーネントに個別に実装するのではなく、アプリケーションのエントリポイントで一度実装できます。
- アプリケーション周辺を保護します。エッジ機能を使用して、アクセス制御やエッジでの高度なジオブロッキングなどのセキュリティ制御を実施できます。これにより、オリジンの攻撃対象領域を減らし、不要なスケーリングコストを取り除くことができます。
- リクエストルーティング。エッジ関数を使用して、アプリケーションロジックに基づいて各 HTTP リクエストを特定のオリジンにルーティングできます。これは、高度なフェイルオーバー、オリジン負荷分散、マルチリージョンアーキテクチャ、移行、アプリケーションルーティングなどのシナリオに役立ちます。
CloudFront のエッジ機能の種類
CloudFront には、CloudFront 関数と Lambda @Edge という 2 種類のエッジ関数があります。CloudFront Functions はミリ秒未満の起動時間を実現し、1 秒あたり数百万のリクエストを処理するように即座にスケーリングできるため、軽量ロジック (キャッシュの正規化、URL の書き換え、リクエストの操作、承認など) に最適です。Lambda @Edge は AWS Lambda の拡張で、リージョンのエッジキャッシュ全体に分散して実行されます。Lambda @Edge は、コストとレイテンシーのオーバーヘッドは高くなりますが、計算能力が高く、外部ネットワーク呼び出しなどの高度な機能も備えています。このドキュメントでは、両方のランタイムの違いについて詳しく説明しています。
エッジ関数を使用して、処理中の HTTP リクエストとレスポンスを操作することも、CloudFront の上流に流す代わりにリクエストを終了してレスポンスを生成することもできます。エッジ関数は、CloudFront でのリクエストのライフサイクル中にさまざまなイベントで実行されるように設定できます。

- ビューワーイベント:CloudFront キャッシュを確認する前に、すべてのリクエストに対して実行されます。キャッシュの正規化、承認、または独自のクッキーの配置に最適です。CloudFront 関数はビューワーイベントでのみ許可されます。
- オリジンイベント:オリジンに行ってファイルを取得する前に、キャッシュミス時に実行されます。キャッシュする前にコンテンツを生成したり、レスポンスを操作したりするのが理想的です。
次のベストプラクティスを使用してください。
- エッジ関数を最も具体的なキャッシュ動作に関連付けて、不要な関数の実行コストを回避します。
- ケースに最適なエッジ関数ランタイムを使用してください。たとえば、ビューワーイベントで CloudFront Functions または Lambda@Edge を使用してロジックを実装できる場合は、CloudFront 関数を使用してください。ロジックをビューワーイベントでは CloudFront Functions、オリジンイベントでは Lambda@Edge を使用して実装できる場合は、キャッシュヒット率が非常に高くない限り、CloudFront 関数を使用してください。
- アプリケーションを設計する際のエッジ機能の制限について学んでください。 ビューワーイベントでは、Lambda @Edge または CloudFront Functions のいずれかを使用できますが、両方を使用することはできないことに注意してください (たとえば、ビューワーリクエストイベントでは Lambda @Edge、ビューワーレスポンスイベントでは CloudFront Functions)。
CloudFront Functions
CloudFront 関数は JavaScript で記述されており、すべてを CloudFront コンソールと API で構築してテストでき、us-east-1 リージョンの CloudWatch ログにログを記録できます。開発者としては、計算使用率が 80% 未満の関数を作成する必要があります。コンピューティング使用率のクォータを超える実行は CloudFront によってスロットリングされ、CloudWatch メトリックスを使用してモニタリングできます。
このプログラミングモデルガイドは、CloudFront 関数を記述するのに役立ちます。以下は、ドイツから来たユーザーをローカライズされたドイツ語コンテンツにリダイレクトする関数の例です。
function handler(event) {
var request = event.request;
var headers = request.headers;
var host = request.headers.host.value;
var country = 'DE';
var newurl = `https://${host}/de/index.html`;
if (headers['cloudfront-viewer-country']) {
var countryCode = headers['cloudfront-viewer-country'].value;
if (countryCode === country) {
var response = {
statusCode: 302,
statusDescription: 'Found',
headers: { location: { value: newurl } },
};
return response;
}
}
return request;
}
CloudFront Functions には、CloudFront KeyValueStore を介して永続データをコードから切り離して保存する機能もあります。KeyValueStore は、バルクリダイレクトマッピングなどの埋め込みデータのために関数のサイズクォータを超過するような状況で特に理想的です。また、関数を変更せずに永続データを更新できるという利点もあります。
Lambda@Edge
Lambda @Edge 関数は NodeJS または Python で記述できます。これにより、構成可能なメモリ (最大 10 GB) を備えた Lambda コンテナの機能を活用できます。AWS Lambda をベースにしているため、Lambda @Edge 関数はラムダコンソールで作成され、us-east-1 でのみ作成されます。作成を完了して CloudFront ディストリビューションにデプロイすると、CloudFront はリージョンエッジキャッシュにグローバルにレプリケートします。Lambda @Edge 関数を CloudFront キャッシュ動作に関連付けるには、まず新しいバージョンを公開し、次にそれをターゲットキャッシュ動作にデプロイする必要があります。Lambda @edge 関数が更新されるたびに、新しい CloudFront デプロイがトリガーされます (最初の関連付けのみが CloudFront デプロイをトリガーする CloudFront Functions とは対照的です)。Lambda @Edge 関数を開発するときは、次の点を考慮してください。
- Lambda @Edge を使用する際のベストプラクティス、特に実行の同時実行の管理について学んでください。同時実行性は、リージョンエッジキャッシュリージョンごとに同時に実行されている Lambda コンテナの数を測定します。各リージョンで、Lambd @Edge の同時実行性には、バースト速度と絶対制限という点で割り当てがあります。
- Lambda @Edge 関数から外部データを取得するためのベストプラクティスについて説明します。
- Lambda @Edge ログは、実行されたリージョンの CloudWatch ログに、us-east-1 というプレフィックスが付いたロググループ名が付いて送信されます。Lambda@Edge ログを 1 つのリージョンに一元化する必要がある場合は、次の Lambda@Edge ログアグリゲーターソリューションを検討してください。関数を実行するたびに CloudWatch Logs にログが生成されることに注意してください (CloudFront Functions では、関数コードに明示的に記述された場合にのみログが生成されます)。Lambda @Edge ログを無効にするには、関連する IAM ロールから CloudWatch にログを送信するアクセス権限を削除します。
このプログラミングモデルガイドは、Lambda @Edge 関数を書くのに役立ちます。 以下は、S3 バケットに保存されているリダイレクトに基づいてリクエストをリダイレクトする関数の例です。
const aws = require('aws-sdk');
const s3 = new aws.S3({ region: 'us-east-1' });
const s3Params = {
Bucket: 'redirections-configuration',
Key: 'redirects.json',
};
const TTL = 5000; // TTL of 5 seconds
async function fetchRedirectionsFromS3() {
const response = await s3.getObject(s3Params).promise();
return JSON.parse(response.Body.toString('utf-8')).map(
({ source, destination }) => ({
source: new RegExp(source),
destination,
})
);
}
let redirections;
function fetchRedirections() {
if (!redirections) {
redirections = fetchRedirectionsFromS3();
setTimeout(() => {
redirections = undefined;
}, TTL);
}
return redirections;
}
exports.handler = async event => {
const request = event.Records[0].cf.request;
try {
const redirects = await fetchRedirections();
for (const { source, destination } of redirects) {
if (source.test(request.uri)) {
return {
status: '302',
statusDescription: 'Found',
headers: {
location: [{ value: destination }],
},
};
}
}
return request;
} catch (_error) {
return request;
}
};