概要
少し前に KAWKAW という架空ショッピングサービスを公開したところ、予想外にバズって想定を大きく超えるアクセスが発生した。
最初は Vercel 単体で運用していたが、アクセス数の増加により Edge Request だけで 1日あたり 10 ドル以上 かかる状態になった。趣味で続けるには厳しいコスト感だったため、Cloudflare を組み合わせて構成を見直したところ、最終的に 1日 1 ドル以下 まで抑えられた。その手法をまとめる。
前提
KAWKAW は基本的に静的コンテンツ中心のサービスで、唯一ユーザー投稿のレビューだけを DB で管理している。
そのため、キャッシュをかなり有効に使える構成になっている。
ただし、そのような「ほぼ静的なサイト」でも、Vercel 単体運用だと思った以上にコストがかかる落とし穴があった。
初期の実装
少人数利用を想定していたため、まずはデプロイしやすさを優先して以下の構成で作成した。
実際に発生していたコスト

ピーク時は Edge Request だけで 1日 16 ドル 発生していた。
VercelのEdge Requestとは?
Vercel の Edge Request は、ネットワークで処理されたリクエスト数に応じて課金される仕組み。
Pro プランでは 月 1000 万リクエストまで無料 だが、それを超えると 100 万リクエストごとに 2〜3 ドル 発生する。
実際の推移は以下の通りで、無料枠を使い切るとアクセスのたびにかなりの料金が積み上がる。

Vercel 自体にもキャッシュ機能はあるが、キャッシュヒット時でも Edge Request としてカウントされる 点に注意が必要。
つまり、Edge Request の課金を抑えるには キャッシュ時にそもそも Vercel へ到達させない 構成が必要になる。
そこで Cloudflare を導入した。
Cloudflareとは
Cloudflare は CDN などを提供するサービス。名前は以前から知っていたが、自分の開発してきたサービスでは使う機会がなく、今回が初導入だった。実際に使ってみるとかなり良く、今後利用機会が増えそうだと感じた。
今回使ったのは以下の 2 つ。
Cloudflare CDN
Cloudflare CDN を使うと、指定したドメインへのアクセスを Cloudflare が中継し、キャッシュが存在する場合は Cloudflare 側からそのままレスポンスを返せる。
キャッシュルールも Cloudflare のコンソールから設定可能。
しかも、複雑なルールを使わない範囲であれば 無料で利用可能。KAWKAW でも無料の範囲で運用できている。
当初は「HTML を Cloudflare CDN でキャッシュすれば、Vercel の Edge Request 問題は解決する」と考えていた。
ただ、実際に導入して様子を見るとキャッシュ率が 30% 前後 までしか上がらず、想定よりかなり低かった。調べたところ、以下の記事を見つけた。
HTTP の標準には Vary というキャッシュ判断に関わるヘッダーがある。
Next.js はキャッシュ制御に Vary を使っているが、Cloudflare は Vary をキャッシュキーの判断に使わない設計 になっている。
この設計差によって、Cloudflare CDN 単体ではうまくキャッシュが効かなかった。
ここを解決するために Cloudflare Workers を使った。
Cloudflare Workers
Cloudflare Workers は、Cloudflare CDN 内部で動作するサーバーレスな JavaScript / TypeScript ランタイム。
Cloudflare CDN までのアクセス経路が以下だとすると、
User → Cloudflare CDN → Vercel
Workers を挟むことで、以下のような構成にできる。
User → Cloudflare CDN → Cloudflare Workers → Vercel
この構成にすることで、Cloudflare Workers 内で問題になっていた Vary ヘッダーを加工 し、Cloudflare 側でキャッシュ可能なレスポンスに変換できるようになった。
Cloudflare Workers の料金体系は 月 1000 万リクエストまで無料。それ以降は 100 万リクエストごとに 0.3 ドル。
単純なリクエスト単価で見ても、Vercel と比べておおよそ 1/6 程度 まで下げられる計算になる。
実際には HTML 以外の静的ファイルは Cloudflare CDN 側で完結するため、体感ではさらに安くなった。
実装後のコスト変化
以下の通り、16 ドル → 0.27 ドル と大幅なコスト削減に成功した。
もちろん Cloudflare Workers 側でも課金は発生するが、それを含めても 1日 1 ドル未満 に収まっている。

まとめ
- Vercel 単体では、キャッシュが効いていても Edge Request 課金が積み上がる
- 静的コンテンツ中心のサイトでは、Cloudflare を前段に置くことで大きくコストを下げられる
- 特に Next.js と Cloudflare の間では
Varyの扱いがネックになりやすく、Cloudflare Workers で吸収する構成が有効 - 最近はコストカット系の開発をやる機会が少なかったので、今回の改善はかなり楽しかった