脳内キャッシュが全然足りてません✧(・ㅂ・)و
こんにちは。クイックSREチームのみっちーです。
今回は、弊社のWebサイトにブラウザキャッシュ設定を実装したときに悩んだ箇所を簡単にまとめてみました。
今回の記事は、こんな人向けです。
- そもそも「ブラウザキャッシュ」ってなんだろう?
- ブラウザキャッシュは知ってるけど、設定方法がよくわからない。
- とりあえず「Webサイトの表示を速くしたい」と思っている。
目次
1. キャッシュとは
最初に、キャッシュについての説明をします。
キャッシュ
プログラム処理結果をディスクやメモリ上に保存し、次回以降に同じ要求が来た場合には計算を省略することで、応答速度の向上を図る仕組みです。
キャッシュと一括りにしても、大きく分けて2種類あります。
- サーバー側で設定するキャッシュ
※ このページでは便宜上、以降は「サーバーキャッシュ」と記します。 - ブラウザキャッシュ
どちらのキャッシュを利用する場合も、
設定自体は基本的にコンテンツを配信するサーバー側で行う必要があります。
サーバーキャッシュ
その名の通り、「サーバー側」に保存されるキャッシュのことです。
DBサーバーやリバースプロキシ等でそれぞれ設定して、応答速度を向上させます。
※ なお今回ここについては詳しく触れません。
メリット
- サーバーの負荷を軽減できる。
- サーバー管理者がキャッシュの動作(有効期間や、キャッシュ対象、ゴミ掃除など)を管理できる。
- Webサイトの表示が速くなる。
デメリット
- 場合により、更新したコンテンツが即時反映されない。これにより、正しい表示がされない事がある。
- AWS CloudFront等のキャッシュ専用サーバーを利用すると、費用が発生する。
ブラウザキャッシュ
一方こちらは「ユーザー端末(PCやスマホ等)」に保存します。ブラウザで見える内容をキャッシュして表示を速くします。
ただし設定自体は基本的に、コンテンツを配信するWebサーバー側で行う必要があります。
開発現場で、「キャッシュが残っている」という表現は、大体がこれを指しています。
メリット
- サーバーの負荷を軽減できる。
- パケット通信量の削減ができる。
- サイトの表示が速くなる。
デメリット
- サーバー管理者がキャッシュの管理ができない。 (有効期間が長いと、ずっと古い表示のまま。)
- キャッシュを溜めすぎると、ブラウザの動作が遅くなる事がある。
2.ブラウザキャッシュの基礎
次はブラウザキャッシュについての基本事項です。
先程も少し触れましたが、ブラウザキャッシュはブラウザで見える内容をキャッシュするものです。つまりHTTPプロトコルで処理できる内容をキャッシュするということになります。
HTTP Response Headers内の指示に従って動く
- HTTPでの要求に対する応答には、必ずHTTP Response Headersが付いています。Response Headers とは、Webサーバーからの応答ヘッダー情報の集まりです。
- キャッシュの動作(有効期間、キャッシュするか否か)は、HTTP Response Headers内に「キャッシュ動作に関するヘッダー」が含まれていて、それに従います。
- この「キャッシュ動作に関するヘッダー」設定はWebサーバー側で行います。
「キャッシュ動作に関するヘッダー」の主な種類
ここがブラウザキャッシュのキモだと思っています。
割りと細かいので、最初は以下だけ抑えておけば良いのでは?と個人的には思います。
最低限覚えておきたいヘッダー。
- Cache-Control ヘッダー
- Expires ヘッダー
余裕があれば覚えておきたいヘッダー。
- ETag ヘッダー
- Last-Modified ヘッダー
Cache-Control ヘッダー
キャッシュをするか否か、する場合には何秒程度キャッシュするかと言った「振る舞い」を定義します。
定義できる「振る舞い」の種類は多いですが、頻出する以下は抑えましょう。
- no-store :
「レスポンス結果の一切をキャッシュしてはいけない」という強い指示です。毎回違う結果を生成するphp処理などは、これを指定する事が多い印象があります。 - no-cache :
「WebサーバーがOKって言わない限りは、キャッシュしないでね」という指示です。基本的にno-storeと同じ内容だと考えれば良いと思います。
「更新が必要かを毎回Webサーバーに確認してね」という指示です。
後述の「ETag ヘッダー」や「Last-Modified ヘッダー」等を利用して、キャッシュの更新が必要かを判断します。
no-storeは一切キャッシュしない(毎回ファイルダウンロードが発生する)動きであるのに対し、no-cacheは更新が無ければキャッシュを利用します。
そのため、「更新確認のためのパケットと時間はかかり」ますが「更新が無ければファイルダウンロードはしない」ので、その分が節約できます。
「ETag ヘッダー」や「Last-Modified ヘッダー」等が適切に配信されていれば、毎回最新の状態をユーザーに返却しつつ速度改善が期待できますが、これらのヘッダーが適切に配信されていないと、意図した動作にならないことがあるため注意が必要です。 - max-age :
有効期間(TTL)の指定を行います。指定は秒です。
ここで指定した秒数以内であれば、次回はサーバーへ確認せずに(ブラウザ)キャッシュを利用し続けます。
0を指定すると、毎回有効期限切れ=データ再取得 となり、実質的にキャッシュをしないという意味合いになります。
Expires ヘッダー
有効期間(TTL)を意味するヘッダーで、 Cache-Control: max-age と同じです。
違いは、HTTPへの実装時期が古いため、より広く(旧ブラウザ)サポートされているという点です。
ちなみにGoogleは、こちらの使用を推奨しています。
ETag ヘッダー
ファイルに更新が有るか否かを確認するためのヘッダーです。
値には、ファイルのバージョンやハッシュが入ります。
毎回Webサーバーへ確認を行いますが、「欲しいファイルが更新されていなければ再ダウンロードは不要」と判断し(ブラウザ)キャッシュを利用します。
※ ファイルダウンロード分のパケットと、時間が節約出来ます。
なお、Cache-Control ヘッダーやExpiresヘッダーと一緒に配信された場合は、Cache-Control ヘッダーやExpiresヘッダーが優先されます。
Last-Modified ヘッダー
ETag ヘッダーと同様の内容ですが、こちらは値に「最後に更新した日付」が入ります。
3. ブラウザキャッシュの設定方法
ここでは、Response Headers 内に上記のヘッダーを設定する方法について書いていきます。
設定は、Webサーバー上で行います。
「Cache-Control : max-age」または、「Expires」 ヘッダー に値を設定する。
Apache
expires_module(mod_expires.c) を利用します。
特にヘッダーの指定はなく、自動で両方のヘッダー項目に値が挿入されます。
以下は、画像ファイルとcss,pdfファイルに対して、アクセス日から1週間ブラウザキャッシュを有効にする設定の例です。
httpd.conf
<IfModule mod_expires.c> ExpiresActive On <FilesMatch "\.(jpg|jpeg|gif|png|ico|tiff|bmp)$"> ExpiresDefault "access plus 7 days" </FilesMatch> <FilesMatch "\.(css|pdf)$"> ExpiresDefault "access plus 7 days" </FilesMatch> </IfModule>
AWS S3
Webサーバーでは無いですが、基本的な考え方はWebサーバーと同じです。
画像配信にS3を使う構成は、最近だと多いと思います。
オブジェクト のメタデータ
以下のいずれかで設定できます。両方書いても良いですし、片方だけでもいいです。
[Cache-Control]
キー項目で上記を選択して、「max-age = 秒数」や、「no-cache」と言った形で値を入力します。[有効期間]
キー項目で上記を選択して、「曜日, 日付 月 年 時間 GMT」で値を入力します。
※ 前述のExpiresヘッダーに該当します。
以下は、Cache-Controlと有効期間の項目にそれぞれ1年で設定した例です。
4. ブラウザキャッシュ設定時のCDNの挙動
ここでは、先程説明したブラウザキャッシュ設定をした状況で、AWS S3やCloudFrontを利用した場合のTTLについて記載します。
構成イメージ
かなり大雑把な図で恐縮ですが、
「WebサーバーとしてEC2を利用し、DBサーバーはRDSを利用。画像はS3に設置して、その上段にCloudFrontがある」という構成で話を進めます。
キャッシュの設定状況
以下のようになっているとします。
S3
今回、画像の配信元(オリジン)サーバーは、S3となりますので、ここでブラウザキャッシュの設定を行います。
- Cache-Control max-age=86400
CloudFront
CloudFrontは、あくまでも「キャッシュサーバー」であるため、サーバーキャッシュの設定となります。
このときの挙動は?
ユーザーが、S3上にあるA.jpgを取得したとします。
このとき、以下のような動きになります。
A.jpg の
- ブラウザキャッシュ期間は、86400秒。
- CloudFrontサーバー上のキャッシュ期間は、43200秒。
つまりユーザーは「S3で設定した値」でキャッシュし、
CloudFrontはCache-Controlの値と比較して短い方を、自身のキャッシュ保持期間として適用します。
※ この場合だと、CloudFrontは43200秒経過したら、S3へ再度A.jpgを取得しに行くという動きになります。DefaultTTLは、Cache-Control(またはExpires)ヘッダーが無いときに使われます。
この辺りがちゃんと理解できていないと、設定中に混乱することがあると思いますので、事前に整理しておくと良さそうです。
いかがでしたか。
ブラウザキャッシュ設定がよくわからないと悩んでいる方の助力になれば幸いです。
それではまた~ (・о・) /