はじめに
こんにちは、Gakken LEAPインフラエンジニアの丹羽です。
今回はCloudfrontのコンテンツ圧縮を検証していた際の失敗談をご紹介したいと思います。
前提
Webサーバーからレスポンスを返す際、コンテンツを圧縮することで転送量を減らしたりレスポンスを高速化したりするテクニックは広く知られていると思います。
AWS Cloudfrontにもコンテンツ圧縮機能があり、S3オリジンの場合は例えば次のような条件下で圧縮されます。
- ビヘイビアで
オブジェクトを自動的に圧縮する
が有効化されている - キャッシュポリシーで
Gzip
またはBrotli
の圧縮サポートが有効化されている - キャッシュポリシーのTTL値が0より大きい値に設定されている
- ビューアーリクエストに
Accept-Encoding
ヘッダーがあり、値にgzip
またはbr
が含まれている - 非圧縮のコンテンツがすでにキャッシュされていない
- オリジンからのレスポンスに
Content-Encoding
ヘッダーがない - オリジンからのレスポンスで
Content-Type
ヘッダーの値がCloudfrontの圧縮するファイルタイプに含まれている - オブジェクトのサイズが1KB~10MBの範囲内
- オリジンからのレスポンスに
Content-Length
ヘッダーが含まれている - オリジンからのレスポンスに本文がある
起きたこと
ある日、サービスで使用しているCloudfrontディストリビューションのビヘイビアを確認したところ圧縮の設定が有効化されていないものがあり、有効化することで転送量を節約できるのではないかと思い、検証を始めました。
前項で挙げた条件を設定後、curlコマンドで圧縮状況を確認します(Cloudfrontのドメインやファイル名は仮のものです)。
curl -I -H 'Accept-Encoding:gzip,br' https://cf.example.com/example.file
ところが、返ってきたレスポンスにContent-Encoding
ヘッダーがありません。サイズもS3オリジンにあるものと変わりないように見えます。つまり圧縮が効いていない…?
先の条件を1個ずつ再確認したり、キャッシュ削除を行なったりしましたが状況は変わらず、その日は進展なく終わりました。
解決
翌日も動作に変化はなかったのですが、ふと思いついて実際にファイルにダウンロードしてみました。
curl -v -H 'Accept-Encoding:gzip,br' -o example.file https://cf.example.com/example.file
すると、レスポンスにContent-Encoding
ヘッダーが付いているではないですか!
何が起きたのでしょう?
これまでの確認では、curlの-I(--head)
オプションを指定していました。このオプションはHEADメソッドでリクエストを送信して、GETメソッドでリクエストした場合に返されるヘッダーのみを取得します。本文は無視されます。
ここで前項のCloudfrontが圧縮を行う条件を思い返しましょう。
オリジンからのレスポンスに本文がある
そうです、HEADメソッドでリクエストした際にはオリジンからのレスポンスにも本文が存在せず、したがって圧縮も行われないのです。
筆者は本文がないというのをうっかりサイズ0のファイルをS3に置いたようなケースを想定していましたが、なんのことはない、うっかり者は筆者の方でした。
ちなみに一度Cloudfrontのエッジに圧縮されたコンテンツがキャッシュされると、それ以降に実行したcurl -I
にはContent-Encoding
ヘッダーが返ってくるようになります。
教訓
今回はcurlでレスポンスヘッダーを取得するには-I
オプションと思い込んでおり、それが実際にはどのようなリクエストを送信しているかということに思い至らなかったのが失敗でした。
期待した結果が返ってこない時にはどうしても焦りがちですが、そういう時こそ冷静に自分の環境を根本から見直したいものです。
エンジニア募集
Gakken LEAP では教育をアップデートしていきたいエンジニアを絶賛大募集しています!!
ぜひお気軽にカジュアル面談へお越しください!!