お知らせ フロントエンド バックエンド インフラ 品質保証 セキュリティ 製品 興味・関心 その他

2023.06.30

インフラ

AWS CloudFrontのキャッシュ効果を計測

要旨

CloudFront+S3+Route53を用いて、CloudFrontによるキャッシングがどの程度応答時間を改善するか計測します。

また、以下のように、CloudFront キャッシュ統計レポートやディストリビューションメトリクスで概要を把握できますが、せっかくなので細かく測定してみました。

構成図

  • S3バケットをオリジンサーバーとしてHTMLファイルを配信します。
  • パブリックアクセスは不可にしています(OACで制御)。

パターン

  • Hit
    CloudFront エッジキャッシュからオブジェクトが提供された時
  • Miss
    オブジェクトがエッジキャッシュに存在せず、CloudFront でオリジンからオブジェクトを取得した時
  • Error
    エラーになり、CloudFront でオブジェクトを提供できなかった時

参考

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/cache-statistics.html

パターン毎の計測対象

  • appconnect_time: リモートホストと SSL/SSH の接続/ハンドシェイクを開始してから完了するまでにかかった時間
  • connect_time: リモートホスト(またはプロキシ) と接続を開始して、完了するまでにかかった合計時間
  • namelookup_time: 名前解決が完了するまでにかかった時間
  • pretransfer_time: ファイルの転送が始まるまでにかかった時間
  • starttransfer_time: 最初のバイトを受信するまでにかかった時間
  • total_time_us: 名前解決, TCP 接続などを含む、以前の転送にかかった合計時間

検証

  • PHP 8.1.15
  • Route53で設定した独自ドメイン(⇒CloudFrontディストリビューション)宛てにリクエストを送信
  • 負荷軽減の為、リクエスト間隔を0.1~1.0秒(ランダム)に設定
  • リクエストは10分間継続
  • パターン毎にかかった平均時間を算出
<?php
const URL = "https://xxxxx";
const BASETIME = [
  "count" => 0,
  "appconnect_time_us" => 0,
  "connect_time_us" => 0,
  "namelookup_time_us" => 0,
  "pretransfer_time_us" => 0,
  "starttransfer_time_us" => 0,
  "total_time_us" => 0,
];
// CloudFrontから受け取るレスポンスヘッダーの一部 "x-cache"の種類
const KIND = ["Hit", "Miss", "Error"];

try {
  $resTime = array_fill_keys(KIND, BASETIME);
  // 10分間ループ
  $start = time();
  $limitSec = 600;
  echo date("H:i:s");
  while ((time() - $start) < $limitSec) {
    $ch = curl_init(URL);
    curl_setopt_array(
      $ch,
      [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_NOBODY => true,
        CURLOPT_HEADER => true
      ]
    );
    $result = curl_exec($ch);
    $info = curl_getinfo($ch);
    curl_close($ch);
    // レスポンスヘッダー"x-cache"の値(種類)を取得
    preg_match('/x-cache: ([a-zA-Z]+)/', $result, $matches);
    if (isset($matches[1])) {
      array_walk($resTime[$matches[1]], function (&$value, $key) use ($info) {
        ($key === "count") ? $value++ : $value += $info[$key];
      });
    } else {
      throw new Exception("non x-cache");
    }
    // サーバー負荷を軽減
    usleep(random_int(100000, 1000000));
    // 残り秒数
    print_r($limitSec - (time() - $start) . "sec" . "\n");
  }

  // 平均値算出 見やすくマイクロ⇒ミリ秒に変換
  $msAvg = [];
  foreach ($resTime as $kind => $val) {
    $msAvg[$kind] = [];
    foreach ($val as $uskey => $us) {
      if ($uskey === "count") {
        $msAvg[$kind]["count"] = $us;
        continue;
      }
      $ms = $us / 1000;
      $msAvg[$kind][explode("_time_us", "avg_" . $uskey)[0] . "_ms"] = $val["count"] ? $ms / $val["count"] : 0;
    }
  }
  
  print_r($msAvg);
  echo date("H:i:s");
} catch (Exception $e) {
  echo $e . PHP_EOL;
  exit;
}

結果

ミリ秒で出力

Array
(
    [Hit] => Array
        (
            [count] => 946
            [avg_appconnect_ms] => 58.846813953488
            [avg_connect_ms] => 9.6629513742072
            [avg_namelookup_ms] => 6.3244545454545
            [avg_pretransfer_ms] => 59.013402748414
            [avg_starttransfer_ms] => 78.120036997886
            [avg_total_ms] => 78.149157505285
        )

    [Miss] => Array
        (
            [count] => 20
            [avg_appconnect_ms] => 74.23295
            [avg_connect_ms] => 28.34885
            [avg_namelookup_ms] => 24.4625
            [avg_pretransfer_ms] => 74.41085
            [avg_starttransfer_ms] => 130.764
            [avg_total_ms] => 130.804
        )

    [Error] => Array
        (
            [count] => 0
            [avg_appconnect_ms] => 0
            [avg_connect_ms] => 0
            [avg_namelookup_ms] => 0
            [avg_pretransfer_ms] => 0
            [avg_starttransfer_ms] => 0
            [avg_total_ms] => 0
        )

)

各項目の整理

各項目の”Hit/Miss*100“は以下の通りです(小数点第二位以下切捨)。

  • avg_appconnect_ms: リモートホストと SSL/SSH の接続/ハンドシェイクを開始してから完了するまでにかかった時間
    • 79.2%
  • avg_connect_ms: リモートホスト(またはプロキシ) と接続を開始して、完了するまでにかかった合計時間
    • 34.0%
  • avg_namelookup_ms: 名前解決が完了するまでにかかった時間
    • 25.8%
  • avg_pretransfer_ms: ファイルの転送が始まるまでにかかった時間
    • 79.3%
  • avg_starttransfer_ms: 最初のバイトを受信するまでにかかった時間
    • 59.7%
  • avg_total_ms: 名前解決, TCP 接続などを含む、以前の転送にかかった合計時間
    • 59.7%

Miss項目が20回と少なかったので、リクエストを増やすなり、キャッシュ削除するなり(意図的にMissさせる)出来れば、結果が著変するかもしれません。

最後に

CloudFrontで、レイテンシーの改善とオリジンサーバーの負荷軽減を実現できます!上手く活用していきたいですね!

株式会社マーケライズ開発チームのOです!車の売却代金はApple製品で消えました!