CloudFront の Origin Shield で S3 へのクロスリージョン参照性能が改善するか試してみた

CloudFront の Origin Shield で S3 へのクロスリージョン参照性能が改善するか試してみた

Lambda Web Functions で別リージョンの S3 を参照したときの遅延改善に、Origin Shield が有効かを検証しました。エッジにキャッシュがない状態でも、クロスリージョンの取得時間が p50 で 170〜330ms 改善しました。
2026.10.21

はじめに

DevelopersIO のフロントは Next.js アプリで、Lambda Web Functions(LWF)のグローバルエンドポイントを使い、複数リージョンで動く構成になりました。

https://dev.classmethod.jp/articles/developersio-lambda-web-functions-multiregion/

著者ページのグラフを描画するため、バージニアに保存した集計済みの JSON を CloudFront 経由で取得しています。

著者ページのグラフ

LWF への切り替え後、グラフの欠落報告が寄せられ、アプリログにも JSON の取得が 500ms でタイムアウトした記録が出ていました。

そこで、Origin Shield で JSON 取得の遅延を解消できるかを検証環境で実測し、LWF 環境に導入した結果を紹介します。

エッジにキャッシュがない状態で取得時間を測る

Origin Shield なしの CloudFront ディストリビューションを作りました。

S3 バケットは us-east-1 に置き、本番の著者別集計 JSON 1,183件から選んだ200件(gzip 圧縮、128〜714バイト)をコピーしました。ディストリビューションはこのバケットを OAC(Origin Access Control)経由で参照します。キャッシュポリシーは、クエリ文字列 k をキャッシュキーに含める独自のものを使いました。k の値を変えると別のオブジェクトとしてキャッシュされるので、キャッシュを無効化しなくても、毎回キャッシュがない状態から測れます。

計測用のキャッシュポリシー(cache-policy.json)
{
  "Name": "oss-verify-cachingoptimized-qs-k",
  "Comment": "Managed-CachingOptimized と同じ TTL・圧縮。クエリ文字列 k だけをキャッシュキーに含める(計測用)",
  "MinTTL": 1,
  "DefaultTTL": 86400,
  "MaxTTL": 31536000,
  "ParametersInCacheKeyAndForwardedToOrigin": {
    "EnableAcceptEncodingGzip": true,
    "EnableAcceptEncodingBrotli": true,
    "HeadersConfig": {"HeaderBehavior": "none"},
    "CookiesConfig": {"CookieBehavior": "none"},
    "QueryStringsConfig": {"QueryStringBehavior": "whitelist", "QueryStrings": {"Quantity": 1, "Items": ["k"]}}
  }
}

計測には AWS Lambda Event Function(従来の Lambda。Node.js 22、メモリ 512MB)を4リージョンに1つずつ置きました。各 Event Function は200ファイルを1件ずつ順に取得し、取得ごとの時間を記録します。1ラウンドの手順は次のとおりです。

  1. クエリ文字列 k を新しい値にする。
  2. us-east-1 の Event Function が200ファイルを取得する。エッジにも Origin Shield にもキャッシュがない状態なので、S3 まで取りに行く。
  3. 残り3リージョンの Event Function が並行して、同じ k で同じ200ファイルを取得する。

手順3のレスポンスの x-cache ヘッダーは、Origin Shield 有効化前は3リージョンとも Miss from cloudfront でした。有効化後はすべて Hit from cloudfront でした。エッジにはキャッシュがないので、このヒットは Origin Shield のものです。つまり、有効化前の値は S3 まで取りに行ったとき、有効化後の値は Origin Shield のキャッシュにヒットしたときの取得時間です。

計測用 Event Function のコード(index.mjs)
// 計測用 Event Function(従来の Lambda)。
// event: { base, prefix, k, files: [..] }
// https://<ディストリビューション>/<prefix><file>?k=<k> を順に取得して所要時間を記録する
const now = () => performance.now();

export const handler = async (event) => {
  const rows = [];
  const url = (f, k) => `${event.base}/${event.prefix}${f}?k=${k}`;
  // 接続の確立(別のキーで取得。計測に含めない)
  try { const w = await fetch(url(event.files[0], "warm-" + event.k)); await w.arrayBuffer(); } catch (e) {}
  for (const f of event.files) {
    const t0 = now();
    let status = 0, ttfb = 0, xc = "", pop = "", bytes = 0;
    try {
      const r = await fetch(url(f, event.k), { signal: AbortSignal.timeout(10000) });
      ttfb = now() - t0;
      status = r.status; xc = r.headers.get("x-cache") ?? ""; pop = r.headers.get("x-amz-cf-pop") ?? "";
      bytes = (await r.arrayBuffer()).byteLength;
    } catch (e) { status = -1; xc = String(e.name); }
    const t = now() - t0;
    rows.push([f, status, +ttfb.toFixed(1), +t.toFixed(1), xc, pop, bytes]);
  }
  return { region: process.env.AWS_REGION, k: event.k, columns: ["file", "status", "ttfb_ms", "total_ms", "x_cache", "pop", "bytes"], rows };
};

計測結果

Origin Shield なし

8ラウンド(各リージョン1,600件)の取得時間(ms)です。

呼び出し元 p50 p90 p95 p99
ap-northeast-1 493.8 512.5 523.3 583.8
eu-central-1 311.7 329.4 339.8 394.5
us-west-2 250.9 271.0 281.5 327.7
us-east-1 45.2 63.8 78.3 129.4

有効化前の ap-northeast-1 は p50 で 493.8ms でした。

Event Function(メモリ 512MB)と比べて LWF は高い CPU 性能が期待できますが、本番で設定しているタイムアウト 500ms に対して余裕がない状態であることが確認できました。

https://dev.classmethod.jp/articles/lambda-web-functions-runtime-environment/

Origin Shield あり

S3 バケットと同じ us-east-1 を指定して、Origin Shield を有効化しました。

有効化後の2ラウンド(各リージョン400件)の取得時間(ms)です。

呼び出し元 p50 p90 p95 p99 p50 の短縮 p95 の短縮
ap-northeast-1 159.5 164.2 165.0 177.0 334.3ms(68%) 358.3ms(68%)
eu-central-1 102.0 104.9 106.1 125.9 209.7ms(67%) 233.7ms(69%)
us-west-2 84.5 91.0 94.9 105.3 166.4ms(66%) 186.6ms(66%)
us-east-1 50.0 67.5 77.8 120.5 − −

Origin Shield を有効にすると、us-east-1 以外の3リージョンで取得時間の短縮が確認できました。

追加費用の見積もり

Origin Shield へのリクエストの料金は、us-east-1 の場合1万件あたり $0.0075 です。

JSON のダウンロードは、実測で多くても1日1万回です。うち3/4が us-east-1 以外のリージョンから Origin Shield を経由すると置いて計算しました。

7,500件/日 × 30日 = 22.5万件 → 22.5 × $0.0075 ≒ $0.17/月

エッジのキャッシュにヒットしたリクエストは Origin Shield に届かず課金されないので、実際はさらに少なくなる見込みです。

まとめ

Origin Shield の有効化により、S3 から小容量のファイルを取得する時間が p50 で 170〜330ms 短くなりました。本番環境にも導入し、問題になっていたタイムアウト(500ms)も概ね解消できました。

Lambda Web Functions で複数リージョン展開し、データソースの S3 を CloudFront 経由で参照している構成で、S3 参照の遅延が問題になる場合は、まず Origin Shield を暫定策としてお試しください。

根本対策としては、S3 をリージョン間でレプリケーションし、最寄りのバケットにアクセスできる Amazon S3 マルチリージョンアクセスポイント(グローバルエンドポイント)が考えられます。こちらも追って評価し、紹介する予定です。

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/MultiRegionAccessPoints.html

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事