エッジ高速化が実際に買っているもの:遅延・経路・キャッシュ
CDN が変えるのは 2 つだけ。パケットが進む距離と、そもそも進む必要があるか。どちらも測定でき、多くのダッシュボードはどちらも正確に測っていません。
この 2 つは別々に書きましたが、同じ問いの両側を扱っています。CDN は結局何を変えるのか。前半は距離です。どのエッジノードが応答するのか、その経路がどれだけ長いのか、数値が実は自分の回線のせいである場合はいつか。後半は必要性です。ヒットすれば要求はオリジンに届かず、ミスすれば直接接続より遠回りになります。両方を並べて初めて、「グローバル高速化」が自分のサイトについて本当かどうかを判断できます。
誰もが ping の数値を口にしますが、それが何を測っているかを知っている人はほとんどいません。往復時間は、通った経路と測定した時刻と併せて初めて意味を持ちます。
1. 光は一瞬では届かない
光ファイバーでは光は 1 ミリ秒でおよそ 200km 進みます。東京からフランクフルトまでは直線で約 9,300km なので、往復の物理的な下限はすでに約 93ms です。ルーターや待ち行列、TLS 握手はまだ含まれていません。これを大きく下回る公表値は、別のものを測っています。
2. エッジノードが教えてくれること
CDN はオリジンではなく最も近い拠点から応答します。同じサイトが都市によって即時にも鈍くも感じるのは、データを保持するサーバーまでの距離ではなく、エッジまでの距離を測っているからです。
3. 併せて測るべきもの
- 平均ではなく分散。安定した 120ms は、平均 60ms でも 400ms まで跳ねる不安定さより快適です。
- パケット損失。1% でも再送を招き、TCP ではスループットが崩壊します。
- 初回のコスト。DNS 参照、TCP ハンドシェイク、TLS ネゴシエーションが、内容を 1 バイトも送る前に複数の往復を消費します。
- 時間帯。輻輳は日内変動があり、同じ経路がピーク時に予測どおり劣化します。
4. 自分で測る
複数回サンプルを取り、すべて保持し、応答したエッジノードと照らし合わせます。ノードが近いのに遅いならボトルネックはラストマイルか手元の回線、ノードが遠いならその数値は地理であって故障ではありません。
5. 自分の回線を疑うべきとき
同じエッジノードで 1 日のうちに遅延が 3 倍違うなら、原因はほぼ確実に CDN ではありません。夜間の輻輳はアクセス網とラストマイルで起きます。確認は簡単で、自分のゲートウェイと公共の目標へ同時に ping を打ちます。ゲートウェイも不安定なら無線かルーター。ゲートウェイが安定していて公共側だけ不安定なら、事業者の出口の輻輳です。この切り分けで、無意味なサポートとのやり取りが 1 回分減ります。
もう 1 つ留意すべき点があります。ブラウザが報告する数値には DNS 解決、TCP ハンドシェイク、TLS ネゴシエーションが含まれます。curl でハンドシェイクだけを計測し、ページ上の数字と比べてください。差が大きいほど初回訪問のコストが高く、プリコネクトの価値が高いということです。
CDN に移行し、ダッシュボードでヒット率 92% を見て安心した矢先、「サイトが遅くなった」と言われる。どちらも事実で、しかも見ている数字は思っているものではありません。
6. まず何が本当にキャッシュ可能か
多くの CDN は拡張子ベースの既定ルールを持ち、画像・フォント・CSS・JS はキャッシュし、HTML はしません。だからサイト全体のヒット率は健全に見えるのに、ページ遷移のたびにオリジンへ戻る、ということが起きます。ダッシュボードは、100 万回の favicon と 1000 回の文書を平均しているのです。
Cloudflare の既定はまさにこの拡張子判定なので、Cache Rule を書かない限り HTML は DYNAMIC で返ります。対処は文書ルートに絞ったキャッシュルールと、意図を明示する Cache-Control です。public、短い s-maxage、そして stale-while-revalidate の窓。
7. ダッシュボードより先にレスポンスヘッダー
開発者ツールでリクエストを開き、cf-cache-status を見ます。HIT はエッジから返った、MISS はオリジンへ行き今後保存されうる、EXPIRED はあったが古い、REVALIDATED はオリジンで検証した、BYPASS は何かが明示的に飛ばした(多くは Cookie、ルール、メソッド)、DYNAMIC はそもそもキャッシュ不可と判断された状態です。6 つのうち 4 つは「ヒットではない」を意味し、バグと言えるのは 1 つだけです。
8. 黙ってキャッシュを無効化する 4 つ
- キャッシュ可能な応答に Set-Cookie が付いている。多くの CDN は Cookie を設定する応答を保存しません。ある利用者のセッションが他者に漏れるからです。HTML テンプレートに解析用 Cookie が 1 つあれば十分です。
- Vary: Cookie。Cookie を設定していなくても、それで変化すると宣言すれば、訪問者ごとに別のキャッシュキーになります。
- 訪問ごとに異なる URL。セッション ID、キャッシュ回避のタイムスタンプ、パスに残った utm パラメータは、1 ページを数千のエントリに分裂させ、それぞれ 1 回だけヒットします。
- Cache-Control: private や no-store。フレームワークの既定値や、障害対応時に書かれて削除されなかったルールが原因のことがあります。
9. ヒット率の高さは目的ではない
ページを 1 日キャッシュすれば 99% にできます。同時に昨日の価格を配ることにもなります。問うべきは「何件がキャッシュから返ったか」ではなく、「キャッシュから返り、かつ正しかったのは何件か」です。再検証の窓を持つ 70% は、更新のたびに手動パージが必要な 99% に勝ります。
サイト全体ではなくルート単位で測ります。ブログ一覧とログイン後の管理画面は同じ数字に混ざり、互いに無関係なのに、平均すると両方の問題を隠します。パステンプレートでログを抽出し、全体平均ではなく最悪の 10 ルートを見てください。
10. 遅延の残り半分
キャッシュヒットでも最寄りのエッジノードまでの往復は必要で、そのノードは Anycast が決めます。データベースの場所ではありません。オリジンが 1 地域にあるなら、地球の反対側からのミスは 2 回の長距離になります。ここが CDN の本領で、正しく設定されたキャッシュが最適化ではなく 40ms と 400ms の差になります。
ipbox.one は実際に応答したエッジ拠点(colo)を遅延サンプルと並べて表示します。測った数字が自分のラストマイルのものか、海の向こうのノードのものかが分かります。