詳説 LightFile Proxy (7) 無駄な変換を避け高速に画像を配信するためのキャッシュ戦略

LightFile Proxyは変換したWebPをCloudFrontとは別に持ち続ける。複数のエッジやリージョンからリクエストが届いても変換結果を使い回せるうえ、期限が切れてstaleになってもHEADひとつで再検証して延命するので、同じ画像を二度変換しない。ひとつの操作で両方のキャッシュを消すクリア、キャッシュクリアだけをサイト運用者に任せる画面、1日1回の自動パージまで説明する。

writer K. Miyanagadate 2026.10.01 (Thu)read 5分cat 画像軽量化, インフラ

WebPへの変換は、1ファイルずつ見れば高速に終わる。それでも画像のフォーマット変換は軽い処理ではないし、何万・何十万ファイルとなれば相応の負荷になる。エンドユーザーには一瞬でも早く軽量化された画像を届けたい。

できる限り変換結果を使い回して、無駄な変換を避けたい。そこでLightFile Proxyは、CloudFrontとは別に自前のキャッシュを持っている。CloudFrontのキャッシュは期限が来れば消えるので、そこだけに頼ると、消えるたびに同じ画像を変換し直すことになるからだ。


キャッシュは二重になっている ​

キャッシュの層を示す構成図。エンドユーザー・CloudFront・LightFile Proxy・オリジンサーバーが横に並び、CloudFrontの下にエッジのキャッシュ、LightFile Proxyの下に変換キャッシュがぶら下がっている

CloudFrontのキャッシュは、アクセスの少ない画像から順に押し出されていく。ロングテールを描くECサイトでは、たまにしか見られない画像ほど消えやすい。

LightFile Proxyの変換キャッシュはクラスタのノード全体で共有している。ここには変換したWebPと、変換しないと決めた画像の判断が入っている。CloudFrontから消えた画像をもう一度求められても、ここに当たれば変換は走らない。

どのエッジから来ても変換は1回 ​

CloudFrontのキャッシュは世界中のPOP(エッジロケーション)ごとに持つ。POPで外れると、CloudFrontは最寄りのリージョナルエッジキャッシュへ取りに行き、そこでも外れたときにオリジンへ来る。AWSのドキュメントにはこう書かれている。

This makes sure that all of the POPs in a region share a local cache, eliminating multiple requests to origin servers.

(これにより、同じリージョンのすべてのPOPがローカルなキャッシュを共有し、オリジンサーバーへの複数回のリクエストが起きないようにする)

つまりリージョンの中ではまとまるが、リージョンをまたげばキャッシュは別になる。同じ画像でも、日本からのアクセスと海外からのアクセスでは、オリジンへのリクエストが別々に届く。そのたびに変換していては無駄が出る。

LightFile Proxyの変換キャッシュはクラスタで1つなので、どのエッジ経由で来ても変換は最初の1回だけで済む。2回目以降は、どこから来ても変換済みが返る。

キャッシュのキーはオリジン側のURL ​

キーにしているのは、エンドユーザーがリクエストしたURLではなく、取りに行くオリジン側のURLになる。

この違いは複数の公開ホストから同じ画像を配信しているサイトで効いてくる。www.example.com と shop.example.com が同じオリジンの同じ画像を指しているなら、キャッシュはひとつで済む。どちらから先にアクセスが来ても、2度目は変換済みが返る。

期限が切れてもHEADひとつで延命する ​

キャッシュには3つの寿命を設けている。

既定値使いどころ
ロング86,400秒(1日)変換済みを返すとき
ショート10秒変換を待っている間にオリジナルを返すとき
エラー300秒オリジンが2xx以外を返したとき

ロングの期限内なら、オリジンには問い合わせずに変換済みを返す。期限を過ぎるとキャッシュはstale(古くなった状態)になるが、staleになったからといってすぐ作り直すわけではない。HTTPのキャッシュと同じように再検証(revalidate)する。

  1. オリジンへ HEAD を送る
  2. 保存したときの etag か last-modified と一致すれば、変更なしとみなして期限だけ延ばす
  3. 一致しなければ、オリジナルを返しつつ変換をやり直す

更新のない画像は2で止まるので、変換のコストは1画像につき1回で済む。再検証で投げるのもHEADひとつなので、画像の本体は取りに行かない。

期限切れのキャッシュを延命する流れのシーケンス図。中継機能がキャッシュに変換済みを探し、期限切れと分かるとオリジンへHEADを送り、etagが変わっていなければ変換済みのWebPを返して期限を延ばす

画像を差し替えたときの追随 ​

オリジン側で画像を差し替えると、etag か last-modified が変わる。次に期限が切れたタイミングで3の経路に入り、新しい画像が変換されて置き換わる。

URLを変えたり、手でキャッシュを消したりする必要はない。 商品画像の差し替えが日常的に起きるサイトでも、運用の手順は変わらない。

ただし、差し替えてから切り替わるまでには期限ぶんの間がある。すぐ反映させたいときは、次のキャッシュクリアを使う。

意図的に消すときはクリア ​

画像を差し替えてすぐ反映させたいときや、間違った画像を配信してしまったときは、キャッシュを消す。この操作をクリアと呼んでいる。

消す前に、消える範囲を見積もれる。 URLの前方一致で条件を指定すると、当たるキャッシュの件数・合計サイズ・実例が返る。この時点では何も消さない。「このディレクトリ以下を消したいが、どれだけ消えるのか」を先に確かめてから、同じ条件で削除に進める。

前方一致はディレクトリの境界で切るので、/shoes/ の指定が /shoes-sale.jpg を巻き込むことはない。

消す順番が決まっている。 まず自分のキャッシュを消し、そのあとCloudFrontへ対応するパスの無効化をリクエストする。逆にすると、CloudFrontが消えた直後にLightFile Proxyの古いキャッシュを取りに行ってしまい、また同じ画像がキャッシュされる。

この2つを、利用者のひとつの操作から続けて実行する。

キャッシュクリアの流れのシーケンス図。サイト運用者が消す条件を指定すると、管理機能が自分のキャッシュを削除し、続けてCloudFrontへ対応するパスの無効化をリクエストして、結果を返す

LightFile Proxy側だけ消してもCloudFrontに古い画像が残っていれば意味がないので、ここまでを一続きにしてある。HTTP APIも用意しているので、入稿のシステムから呼ぶこともできる。

クリアだけをサイト運用者に任せられる ​

画像の差し替えをすぐ反映させたい場面は、サイトを日々まわしている人のところで起きる。ところがLightFile Proxyの管理画面にはオリジンの設定やCloudFront連携が並んでいる。そこを開いてもらうのは、操作ミスの心配があって気が進まない。

そこでキャッシュクリアだけができる画面を別に用意している。

サイト運用者向けの簡易画面。サイト名とキャッシュクリアの入力欄だけがあり、消したい画像のURLまたはパス条件を複数行で指定してボタンを押す形になっている

できるのは、登録されたサイトのキャッシュを消すことだけになる。設定はどこにもなく、触れる範囲はそのサイトの画像に限られる。サインインはGoogle・Microsoftのアカウントか、メールに届く一時リンクで、許可するメールアドレスは個別でもドメイン単位でも指定できる。

日々の反映で毎回インフラの担当者を呼ばなくてよくなる。 複数のサイトを預かっている代理店なら、サイトごとの担当者に消す操作だけを渡せる。

確保した容量に収めるのはパージ ​

クリアが運用者の意図で消す操作なのに対して、パージは容量へ収めるため自動で走る掃除になる。目的が違う。

キャッシュに使う容量は、クラスタごとに決めて確保する。既定は200GBで、足りなければ追加の費用で増やせる。大きく取るほど、たまにしかアクセスされない画像も残り続けるので、変換のやり直しが減る。

確保した容量を超えたからといって、その場で止めたり消したりはしない。超えた分はひとまず受け入れておき、1日1回まとめて収める。 パージは毎日03:00(JST)に走り、最終アクセス日時の古い順に、確保した容量へ収まるところまで削除する。よく見られている画像は残り、誰も見なくなった画像から消えていく。

キャッシュ容量の推移を示す折れ線グラフ。確保した容量200GBの赤い破線を日中に超えていき、毎日03:00のパージで200GBまで戻る動きを繰り返している

増やしている例もある。400GBで確保しているクラスタが466GBまで膨らんでいて、35,513件(42GB)を削除して戻したことがあった。最大のクラスタは約530万件のキャッシュを抱えていて、3TBを確保している。