CloudFrontで「Forward Cookies」を「All」にしている時に注意すべき点

Amazon_CloudFront

菅野です。

先日、CloudFront経由でウェブページにアクセスした時に常に「X-Cache: Miss from cloudfront」となるので調査したところ、CloudFrontの「Behavior」の「Forward Cookies」が「All」になっている事が原因でした。

今回はなぜ「All」だとキャッシュが使われなかったのか、CloudFrontにおけるcookieの注意点について書こうと思います。

webページを準備

EC2インスタンスを立ち上げ、apacheとphpをインストールします。
/var/www/html/index.phpを作成し、内容は以下にします。
GoogleAnalyticsもcookieを使うので検証の為に埋めました。

<?php
  setcookie( "cookie01", "value01" );
//  setcookie( "cookie02", date('Y/m/d H:i:s') );
  setcookie( "cookie02", "" );
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>テストwebページ</title>
</head>
<body>
<span>これはテストページです</span><br>
<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-********-*', 'auto');
  ga('send', 'pageview');

</script>
<br>
------------------------------------------------------<br>
cookie<br>
------------------------------------------------------<br>
<?php
  $tmp_str = json_encode( $_COOKIE );
  $tmp_str = preg_replace( '/([,{])/', '${1}'."\n".'<br>', $tmp_str );
  $tmp_str = preg_replace( '/}/', "\n".'<br>}', $tmp_str );
  echo $tmp_str;
  echo '<br>';
?>
------------------------------------------------------<br>
</body>
</html>

このページにアクセスすると以下のような結果が得られ、webサーバーにどのようなcookieが渡されているか確認できます。
webサーバー直

CloudFrontを準備

CloudFrontのページを表示し、「Create Distribution」をクリックして新しく「Distribution」を作成します。
作成は簡単で、「Origin Domain Name」に先ほど作成したEC2の「パブリック DNS」を入力するだけでOKです。
Distribution作成

CloudFrontは作成が完了するまで時間が掛かります。設定を変更した時も同様なので実際に試す時はその点を覚悟してください。

「Forward Cookies」が「None」の場合

「Forward Cookies」はデフォルトで「None」になっていて、この状態はoriginに指定したwebサーバーに対して一切cookieを渡しません。
Forward_Cookies_None

では、CloudFrontを経由して先ほど作成したwebサイトにアクセスして確認してみましょう。
URLはCloudFrontの「Domain Name」になります。
CloudFront一覧

結果は以下のようになり、webサーバーに対してcookieが一切渡されていない事がわかります。
Forward_Cookies_None_web

次に、数回更新した後でchromeの基本機能を使ってCloudFrontのキャッシュが使われているか確認します。
確認用URL:chrome://net-internals/#events
「type:URL_REQUEST」でフィルタすると使いやすいのでおすすめです。
net-internals

結果は以下のようになります。
Forward_Cookies_None_Hit
HTTPヘッダに「X-Cache: Hit from cloudfront」と表示されていますので、キャッシュされてそれを使ったことがわかります。

「webサイトでcookieを使いたいのに渡ってこないのでは困る」といった場合は「Forward Cookies」を「None」で運用できません。
では「All」での運用はどのような状況になるか検証してみましょう。

「Forward Cookies」が「All」の場合

Forward_Cookies_All

さっそくこの状況で何回かアクセスしてみましょう。結果は以下のようになります。
Forward_Cookies_All_page
表示内容はwebサーバーに直接アクセスした時となんら変わりませんね。
ではHTTPヘッダはどうなっているのか確認します。
Forward_Cookies_All_header
キャッシュにHitしています。この状態で問題無さそうに見えますがCloudFrontはcookieの値も含めてキャッシュを使うか判断していますので値が異なる場合はキャッシュが使われません。
その部分を理解する為にwebページのソースを少し変更し、3行目のコメントアウトを解除し、4行目をコメントアウトします。

<?php
  setcookie( "cookie01", "value01" );
  setcookie( "cookie02", date('Y/m/d H:i:s') );
//  setcookie( "cookie02", "" );
?>
<!DOCTYPE html>
<html lang="ja">
略

この状態で何度かアクセスしてみましょう。以下のようにcookieに日時が登録されていて、アクセスする度に変更されている事もわかります。
Forward_Cookies_All_page_2

では、このようにアクセスする度にcookieの値が変わるページの場合、CloudFrontのキャッシュは使われのでしょうか?
先ほどと同じようにHTTPヘッダを確認します。
Forward_Cookies_All_header_2
X-Cache: Miss from cloudfront
X-Cache: Miss from cloudfront
X-Cache: Miss from cloudfront
何度アクセスしてもキャッシュが使われません。
「Forward Cookies」が「All」で「cookieの値が変動した時」はCloudFrontは別のキャッシュを作成するので前回のキャッシュは使われないのです

ではどんな問題が?

さきほど、「Forward Cookies」が「All」の場合はcookieの値によって別キャッシュとなる事がわかりました。
ではどんな問題があるの?と言われると運用しているwebサイトによっては問題ないかもしれませんが、最早入れててあたりまえという感じのGogleAnalyticsタグはどうでしょう?
まずは日時のcookieを無効化し、今度は別のブラウザでアクセスしてみます。
Forward_Cookies_All_page_safari
「_ga」の値が変わっています。
chrome:GA1.3.1433833158.1463106328
safari:GA1.3.1375323490.1463121195
キャッシュが本当に使われていないのか、safariで数回アクセスした後すぐにchromeでアクセスしてみます。
Forward_Cookies_All_page_safari2chrome
Missとなりました。もちろん、もう1回アクセスするとHitになります。

このように、「Forward Cookies」が「All」で「GoogleAnalytics」のタグを埋めている場合、各ユーザーさらに各ブラウザ毎にキャッシュが作成されるのでHit率が悪くなります。

ではどうすればいいの?

CloudFrontの「Forward Cookies」には「Whitelist」というものも用意されています。
ここに「GoogleAnalyticsのCookie以外」を登録すればいいのです。
whitelist
ページにアクセスしてwebサーバーに渡っているcookieを確認します。
Forward_Cookies_Whitelist_page
GoogleAnalyticsのcookieは渡されていません

この状態でSafariから数回、すぐにchromeからアクセスして確認します。
Forward_Cookies_Whitelist_header
このようにCloudFrontのキャッシュが使われました。

さいごに

いかがでしたでしょうか。
今回このエントリーを書くきっかけは、「CloudFrontでキャッシュにHitしない」という問題の調査でした。
Google先生に幾度となく質問をしたのですが、CloudFrontのキャッシュのTTLについてのエントリーは多数出てくるけど「CloudFrontがキャッシュしない条件」についての情報が見つからないという状況で、
単純なページを作成して検証するとキャッシュされ、問題のページのソースをコピーするとキャッシュされないことがわかり、ためしにGoogleAnalyticsのタグを消してみたらキャッシュされました。

世の中でこれだけ使われているGogleAnalyticsとCloudFrontの組み合わせで問題が起きていないのか?とも思いましたが、「None」で使っている場合は問題ないですし、ブラウザを変えるとキャッシュがHitしないが2回目からはHitするので、Hit率が悪くなっている事に気づいていない可能性もあります。

CloudFrontを「Forward Cookies」に「All」や「Whitelist」を設定して利用する時は、cookieに何が渡されているのかを確認し、場合によっては「Whitelist」を使って必要なcookieだけを渡す設定が必要だという事を覚えておいてください。

このエントリーを見た方がCloudFrontの「Forward Cookies」について確認・検討するきっかけになれば幸いです。

参考ページ

これらのページを参考にさせていただきました。
ありがとうございました。
[Server & Network] Chrome Developer Tools で HTTP Header を確認する方法
Cloudfrontでヘッダー情報が更新されないとかその手のもの
ふつうのWebサイトの負荷軽減におけるCloudFront