目次
概要
ウェブ開発においてキャッシュ(Cache)は重要な役割を果たします。キャッシュを通じてウェブサービスのパフォーマンスを向上させることができ、ユーザーエクスペリエンスを改善することができます。今回のブログポストでは、ウェブ開発におけるキャッシュ(Cache)について説明をして、AWS S3に静的ファイルでウェブサービスを提供する際にキャッシュを適用する方法について説明します。
ウェブキャッシュの誕生背景
クライアント(PC、スマートフォン)からサーバーにある情報を取得するためにはインターネット(Internet)を使います。
クライアントとサーバーを接続するインターネットは物理的に接続されており、世界中のインターネットは海底ケーブルで接続されています。
クライアントとサーバーはこのように物理的に接続されているため、もちろん距離が遠いほどデータの送受信に時間がかかることになります。
ウェブキャッシュ
ウェブキャッシュは物理的に遠い場所にあるサーバーのコンテンツのうち、変更が少ないコンテンツ(静的コンテンツ: HTML、CSS、JS、画像、ビデオなど)を物理的に近い場所(サーバー)にコピーして配置することでデータの送受信の遅延を減らす技術です。
ウェブでは大きく3つのキャッシュを使用します。
- CDN(Contents Delivery Network)
- ブラウザキャッシュ(Browser cache)
- データベースキャッシュ(Database cache)
今回のブログポストではCDNとブラウザキャッシュについて説明します。
CDN(Contents Delivery Network)
CDNは変更が少ないコンテンツのコピーを世界中の複数の場所にあるサーバーに配置してコンテンツを提供するサービスです。
これを通じてクライアントとサーバー間の距離を縮めてデータの送受信の遅延を減らすことができます。
例えば、世界的に有名なCDNサービスであるCloudflare
は次のように世界中にサーバーを置いています。
Cloudflare
を利用すると静的ファイルをCloudflare
が提供するサーバーにコピーしてクライアントと近いサーバーからコンテンツを提供することができます。
ブラウザキャッシュ(Browser cache)
クライアント側から見ると最も近いサーバーはクライアント自体です。ブラウザはクライアントが一度アクセスしたサイトから一部のコンテンツをクライアントストレージに保存して再度アクセスする際にこの保存されたコンテンツを使えるようにするブラウザキャッシュ機能を提供します。
Chromeブラウザの場合次の場所にキャッシュをします。
- Windows:
C:\Users\<User Name>\AppData\Local\Google\Chrome\User Data\Default\Cache
- macOS:
/Users/<User Name>/Library/Caches/Google/Chrome/Default/Cache
ウェブキャッシュの動作方法
ウェブキャッシュがどのように動作するかについて説明します。
- ユーザーがブラウザからサービスにアクセスします。
- ブラウザはブラウザにキャッシュされたものがあるか確認し、キャッシュがある場合はそれを使って画面を表示します。
- ブラウザにキャッシュがない場合はCDNにキャッシュがあるか確認します。CDNにキャッシュがある場合はそれを使います。
- CDNにキャッシュがない場合は実際のサーバーからコンテンツを取得します。
- このときCDNはキャッシュをする必要があるかどうかを確認し、キャッシュできる場合はキャッシュします。
- ブラウザも同様にキャッシュできる場合はキャッシュします。
- 次からユーザーが同じコンテンツにアクセスする時、ブラウザとCDNでキャッシュされたコンテンツを使います。
ウェブキャッシュの設定
ブラウザとCDNはどの基準でキャッシュを設定するでしょうか?ブラウザとCDNはHTTPレスポンスヘッダーにあるExpires
、Cache-Control
、Etag
、Last-Modified
などを確認してキャッシュを設定します。
HTTPレスポンスヘッダーにキャッシュを設定する方法は次のようになります。
- Nginxの設定
server {
listen 80;
server_name example.com;
location / {
# Set Cache-Control
add_header Cache-Control "max-age=3600, public";
# Set Expires
expires 1h;
}
}
- ウェブサーバーの設定(NodeJSのExpress例)
const express = require('express');
const app = express();
app.use((req, res, next) => {
// Set Cache-Control
res.setHeader('Cache-Control', 'max-age=3600, public');
// Set Expires
const maxAgeInSeconds = 3600;
const date = new Date();
date.setSeconds(date.getSeconds() + seconds);
const expiryDate = date.toUTCString()
res.setHeader('Expires', expiryDate);
next();
});
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
このように設定されたHTTPレスポンスヘッダーを確認してCDNとブラウザがキャッシュを設定します。
AWS S3とCloudFront
AWSのS3とCloudFrontを使って静的ウェブサイトを提供することができます。
- S3(Simple Storage Service): 静的ファイルを保存するサービス
- CloudFront: CDNサービス
S3はストレージサービスですが、静的ファイルでウェブサービスを提供するサーバー機能も提供しています。
一般的にHTML、CSS、JavaScriptで開発された静的ウェブページやReact、Vue、Angularなどのフロントエンドフレームワークで開発されたウェブアプリケーションのビルド結果をS3にアップロードしてCloudFrontを通じてサービスします。
この時、S3にアップロードしたファイル設定を通じてブラウザキャッシュとCDN(CloudFront)キャッシュを設定することができます。
AWS S3キャッシュ設定
キャッシュはHTTPのレスポンスヘッダーにExpires
やCache-Control
を設定するため、基本的にフロントエンド側で設定することはできません。
CloudFront + S3
はサーバーがないためHTTPヘッダーを設定するサーバーコードを追加することはできません。
しかし、S3
がサーバー機能を持っているため、S3の設定を通じてキャッシュを設定することができます。
AWSが提供するCLIツールを使ってS3にファイルをアップロードする際、次のようなコマンドを使います。この時、--cache-control
オプションを使うことでキャッシュを設定することができます。
aws s3 cp <Target directory> s3://<S3 Bucket name> --recursive --exclude "assets/*" --cache-control 'public,max-age=60,stale-while-revalidate=2592000’
Target directory
: S3にアップロードするビルド結果があるローカルフォルダのパスS3 Bucket name
: ファイルをアップロードする対象となるS3のBucket名--recursive
オプション:aws s3 cp
は基本ファイル1つをコピーするコマンドなので、指定されたディレクトリのすべてのファイルをアップロードするために--recursive
オプションを使います--exclude "assets/*"
: アップロード除外対象の設定--cache-control 'public,max-age=60,stale-while-revalidate=2592000'
: キャッシュ設定max-age=60
: 60秒間キャッシュstale-while-revalidate
:max-age
によってキャッシュが終了した場合、バックグラウンドでコンテンツを再確認してキャッシュする間、期限切れのキャッシュを最大30日間提供するように設定
GitHub Actions
次はGitHub Actions
を使ってS3にファイルをアップロードするコードです。
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: $
aws-region: ap-northeast-1
- name: Upload file to S3
run: |
aws s3 rm s3://$ --recursive
aws s3 cp apps/dist s3://$ --recursive --exclude "assets/*" --cache-control 'public,max-age=60,stale-while-revalidate=2592000'
aws s3 sync apps/dist/assets s3://$/assets --cache-control 'public,max-age=60,immutable'
aws s3 rm
を使ってすべてのファイルを削除した後、aws s3 cp
を使ってファイルをアップロードします。最後にassets
フォルダをaws s3 sync
を使ってアップロードします。
stale-while-revalidateを使った無中断デプロイ
AWSのブログで紹介された使い方です。
stale-while-revalidateを使うと中断なしにサービスバージョンを更新することができます。
- ユーザーがブラウザでサービスを実行します。
- V1で既にサービスを利用しているユーザーは、ブラウザにstale-while-revalidateが設定されたV1のキャッシュがあるため、それを優先して使います。
- ブラウザはバックグラウンドでキャッシュが終了した(max-age)コンテンツをCloudFront(CDN)に要求します。
- CloudFrontはV2に更新されたキャッシュがあるため、それをブラウザに提供します。
- ブラウザはCloudFrontから受け取ったコンテンツをキャッシュして次からこれを使います。
- もし、CloudFrontのキャッシュも更新が必要な場合(max-age)、まずはstale-while-revalidateが設定されたV1のキャッシュをブラウザに提供した後、バックグラウンドで実際のサーバーからコンテンツを取得して自身のキャッシュを更新します。
完了
これでウェブキャッシュ(Web cache)について説明をして、AWS S3とCloudFrontを使って静的ファイルでウェブサービスを提供する際にキャッシュを適用する方法について説明しました。
このブログポストがウェブキャッシュの理解とAWSでウェブキャッシュを適用する際に役立つことを願います。
私のブログが役に立ちましたか?下にコメントを残してください。それは私にとって大きな大きな力になります!
アプリ広報
Deku
が開発したアプリを使ってみてください。Deku
が開発したアプリはFlutterで開発されています。興味がある方はアプリをダウンロードしてアプリを使ってくれると本当に助かります。