こんにちはjunです。RouteShareというユーザー投稿型の個人開発でユーザーがアップロードしたファイルをS3に配置し、cloudfrontでキャッシュを効かせて取得するように設定しました。このときユーザーアバターや投稿コンテンツの自動生成サムネイルなど特定のファイルは{ID}.png
のようにDB上のIDと拡張子で表現していました。IDベースのファイル名にすることでIDさえわかればユーザーや投稿のサムネイルが表示できるというメリットがありました。
しかし上記の方法ではファイル名が変わらず、更新した際のcloudfrontのキャッシュで画像が切り替わらないという事態がありました。今回はこのような「cloudfront上で同じ名前で管理しているが、都度更新があった際に確実に更新したファイルを表示させる方法」についての内容です。
まず最初にcloudfrontにはサービス上でキャッシュを削除する機能はあります。指定のパスを設定することで、キャッシュさせたURL(ここではファイルURL)をcloudfront上から削除することができます。キャッシュがなくなるのでオリジンに取得しにいき、更新したコンテンツを取得できます。しかしそれをコンテンツごとに行うのは大変です。単純に数も多いですし更新があったコンテンツを検知して、APIでcloudfrontの操作を行う必要があるからです。また無料枠分はありますが、キャッシュの削除にはお金がかかります。
cloudfrontは実はキャッシュは効かさないこともできますが、折角のCDNが勿体無いです。更新を効かしつつも普段はキャッシュさせてパフォーマンスを上げる方法としては、ファイル名に?ver=xxxx
のようなクエリパラメータをつけて、別のURLとして認識させる方法があります。これはcloudfrontのみならず、他のキャッシュ対策でもよく行われます。バージョンパラメータはクライアント側で制御します。例えば、ユーザーアバターの際はアップロード更新時にユーザーレコードのupdated_atを更新し、ユーザーレコードを参照する箇所ではそのupdated_atをクエリパラメータに入れます。ビルドしたjsやcssなどにはビルド日時とかを入れられるようにするといいかもしれません。
ただし、cloudfrontのデフォルトのキャッシュポリシーであるCachingOptimizedはこのクエリパラメータを考慮しません。どんなクエリパラメータをつけようが、同じファイル名であればキャッシュしてしまいます。そのため、新しいキャッシュポリシーを加えます。
最初にcloudfrontの画面を開き、ポリシーを選択します。
カスタムポリシーからキャッシュポリシーを作成を選択
クエリパラメータを有効にしたい既存のキャッシュポリシーと同じにします。今回はデフォルトのCachingOptimizedとTTLや圧縮サポートを選択。そして 「キャッシュキー設定」にてクエリ文字列を追加し、扱うパラメータを入力します。ポリシー名を設定し、問題なければ作成をクリックしてポリシーを登録します。
次にポリシーを当てはめたいディストリビューションのビヘイビアを編集します。
キャッシュポリシーを先ほどの名前のものに設定します。
変更を保存をクリックして完了です。こうすれば?ver=2022-12-01-00-00-01
から?ver=2022-12-01-00-00-02
に変更した際に別のリソースとして認識され、オリジンへの取得が行われ再度そのクエリパラメータと共にキャッシュされます。
これの良い点は更新日時に応じてほぼ確実にキャッシュを殺すことができると同時に、次の更新まではキャッシュが効くようになることです。ヘッダー・クッキーでは容易にバージョンパラメータを追加するのが難しいので、ファイルであればクエリパラメータがおすすめです。
ちなみにパラメーターパターンに対するキャッシュは効いているので、?ver=2022-12-01-00-00-01
から?ver=2022-12-01-00-00-02
に変わったとして?ver=2022-12-01-00-00-01
でアクセスするとキャッシュ期限まで古いものが表示されます。そのため「更新されたら必ず過去のキャッシュは消えるようにしないといけない」という場合は上記のcloudfrontでのキャッシュ削除が必要です。