ネットワーク●●●○○

CDN

CDN ・ しーでぃーえぬ

世界中のエッジサーバにキャッシュを置き、近い場所から配信して速度と負荷を改善する仕組み。

✦ 30秒で試す — 航海サーバーは北米に1台なのに、地球の裏側でも速い止まった直後、エッジ経由でページを開く利用者は?予想してみる

概要

CDN(Content Delivery Network)は、世界中に配置した多数のサーバ(エッジサーバ)にコンテンツのキャッシュを置き、利用者に地理的に近い場所から配信するネットワークです。コンテンツの本来の置き場所である自分のサーバは「オリジン」と呼ばれ、CDN はその代理人として利用者の近くに立ちます。利用者はいつもの URL にアクセスするだけで、裏で最寄りのエッジにつながります。

効果は二重です。まず速さです。光ファイバーの中の信号にも速度の限界があるため、東京の利用者が米国のサーバから取得すると往復だけで100ミリ秒以上かかりますが、都内のエッジからなら数ミリ秒で済みます(この往復の待ち時間がレイテンシです)。次に負荷です。大半のリクエストがエッジで完結するため、オリジンには全体のごく一部しか届かず、アクセスが急増しても耐えられます。

Cloudflare・Akamai・Amazon CloudFront・Fastly が代表例です。画像や JavaScript・CSS の配信という古典的な用途に加え、いまでは TLS の終端、DDoS攻撃の吸収、エッジ上でのコード実行まで、「サイトの入口」全般を担う存在になっています。

なぜ生まれたか

1990年代後半、Web の利用者が急増すると、2つの問題が深刻になりました。1つは距離です。コンテンツは1か所のサーバに置かれているのに利用者は世界中にいるため、遠い地域からは表示が遅くなります。もう1つは集中です。人気の記事やニュース速報にアクセスが殺到すると、1か所のサーバと回線では捌ききれずにサイトが落ちます。いわゆる「フラッシュクラウド」問題です。

1995年ごろ、Web の考案者ティム・バーナーズ=リー(当時 MIT)が、この混雑を根本から解く方法を同僚たちに問いかけました。これに取り組んだ MIT のトム・レイトンと大学院生ダニエル・ルーウィンらが、1998年に Akamai を創業します。アイデアは「コンテンツのコピーを世界中に置き、利用者を最寄りのコピーへ誘導する」ことでした。静的なコンテンツは誰に配っても同じなので、コピーを各地に置いても矛盾しません。この性質を使って、距離の問題と集中の問題を同時に解いたのが CDN です。

詳細

最寄りのエッジへ誘導する仕組み

CDN の第一の仕掛けは「利用者をどうやって近くのエッジにつなげるか」です。代表的な方式は DNS を使います。サイトのドメインを CDN 事業者のドメインへの CNAME にしておくと、名前解決のときに CDN 側の権威サーバが問い合わせ元の位置を判断し、最寄りのエッジの IPアドレスを返します。もう1つがエニーキャストで、世界中のエッジが同じ IP アドレスを BGP で広告し、インターネットのルーティングによってパケットが自然に最寄りの拠点へ届く仕組みです(Cloudflare が代表例)。どちらの方式でも、利用者は何も意識しません。

キャッシュヒットとキャッシュミス

エッジに着いてからの動きは、キャッシュの典型例です。エッジがコンテンツのコピーを持っているかどうかで、経路が分かれます。

利用者東京エッジサーバ利用者の最寄り拠点キャッシュを保持オリジンサーバ米国・遠い本来の置き場所数msリクエストヒット時はここで折り返して即応答、オリジンへは行かない数千km・往復100ms以上ミス時のみ取得応答を返すミス時はエッジが応答を保存し、以降の同一リクエストはヒットになるオリジンまで往復するのは、その拠点で最初の1人だけ
ヒット時は最寄りのエッジで折り返し、ミス時だけ遠いオリジンまで取得に行く

持っていれば(キャッシュヒット)その場で応答して終わり、オリジンには一切アクセスしません。持っていなければ(キャッシュミス)、エッジがオリジンまで取りに行き、応答を利用者へ返すと同時に手元に保存します。次に同じコンテンツを求める利用者からはヒットになります。つまり、オリジンまでの往復のコストを払うのは、その拠点で最初の1人だけです。

どれだけの時間キャッシュしてよいかは、オリジンが返す HTTP の Cache-Control ヘッダで指示します。max-age はブラウザも含めたすべてのキャッシュ向け、s-maxage は CDN のような共有キャッシュ向けの有効期限(秒)で、この期限が TTL(Time To Live)になります。全リクエストのうちエッジで捌けた割合を「キャッシュヒット率」と呼び、CDN 運用で最も大切な指標です。

下の部品で、エッジを地域に置いてリクエストの粒を流してみてください。最初の1回だけオリジンまで往復し、あとはエッジで折り返すこと。そしてオリジンのファイルを更新したとき、エッジが何を配り続けるかを確かめてください。

⚡ 体験: エッジを置いて、どこで折り返すかを見る
北米欧州アジア大陸をまたぐ長い道(往復 150〜260ms)オリジンv1/news.htmlmax-age=300押すと止まるエッジの置き場エッジの置き場エッジの置き場———地域の点線の枠へドラッグ(タップでも置ける)エッジ
エッジのヒット率—オリジンまで行った割合—平均応答—
リクエスト応答(v は版)朱の破線の輪=古い版・朱の粒=失敗エッジで折り返す短い道

「エッジ」のチップを地域の点線の枠へ運んで置いてください(タップでも置けます)。いまはすべての利用者が北米のオリジンまで直行していて、アジアからは往復で約 276ms かかっています。

キャッシュキーと Vary

エッジが「同じコンテンツ」かどうかを判断する物差しが、キャッシュキーです。既定ではスキーム・ホスト・パス・クエリ文字列を組み合わせたもの、つまりほぼ URL そのものです。このため、?utm_source=... のような広告計測用のパラメータが付くだけで別のキーになり、ヒット率が下がります。多くの CDN は、キーに含めるクエリやヘッダを設定で絞れるようになっています。

応答の中身がリクエストヘッダによって変わる場合、オリジンは Vary ヘッダでそれを宣言します。たとえば Vary: Accept-Encoding なら、gzip 版と Brotli 版を別々に保存します。ここで Vary: Cookie や Vary: User-Agent のように値の種類が膨大なヘッダを指定すると、利用者ごとに別のコピーができてしまい、キャッシュは事実上効かなくなります。

オリジンシールドと stale-while-revalidate

エッジは世界に数百か所あるので、TTL が切れるたびに各拠点が一斉にオリジンへ取りに行くと、それだけでオリジンに負荷の山ができます。そこでエッジとオリジンの間に、もう1段の中間キャッシュ(オリジンシールド)を置く構成がよく使われます。エッジのミスはまずシールドに集まり、シールドがオリジンへ取りに行くのは1回だけで済みます。同じキーへの同時のミスを1本のリクエストにまとめる「リクエストの合流(collapsing)」と組み合わせると、オリジンに届くのは本当にわずかになります。

利用者の近く(数百拠点)エッジ 東京エッジ 大阪エッジ ソウルエッジ 台北各エッジのミスオリジンシールド中間キャッシュ・1拠点1本だけオリジン本来の置き場所同じキーへの同時のミスは合流させて1本にするオリジンの負荷は、拠点の数よりキーの数に比例する
オリジンシールド: 各地のエッジのミスを中間の1段で受け止め、オリジンへの取得を1本にまとめる

TTL が切れた瞬間の待ち時間を隠す仕組みもあります。Cache-Control: max-age=60, stale-while-revalidate=300 と返すと、期限切れから5分のあいだは、エッジは古いコピーをすぐに返しつつ、裏でオリジンへ取り直しに行きます(RFC 5861)。利用者は待たされず、次の人からは新しい版が届きます。同じ RFC の stale-if-error は、オリジンが落ちているあいだ古いコピーで応答し続けることを許すもので、オリジン障害の緩衝材になります。

キャッシュ無効化という難問

CDN 運用の最大の落とし穴は「古いコンテンツが配られ続ける」ことです。オリジンのファイルを更新しても、エッジのキャッシュは TTL が切れるまで古いままです。対策の定石は2つあります。急ぐときは「パージ」、つまり CDN の API でキャッシュを明示的に消す操作です。より根本的なのが「キャッシュバスティング」で、ファイルの中身から計算したハッシュをファイル名に含め(app.a1b2c3.js のように)、更新のたびに別の URL として配信します。URL が変われば古いキャッシュは参照されなくなるので、静的アセットには「1年キャッシュ+ハッシュ付きファイル名」、それを参照する HTML は短い TTL、という組み合わせが事実上の標準です。

逆向きの事故もあります。ログイン中の利用者ごとに内容が変わるページや、Cookie に依存する応答を誤ってキャッシュすると、ある人の個人情報がほかの人に配られる重大事故になります。個人向けの応答には Cache-Control: private か no-store を付け、「何をキャッシュしてよいか」を URL の単位で設計しておくことが、CDN 導入時の最初の仕事です。

静的配信からエッジコンピューティングへ

現代の CDN は配信以外の役割も抱えています。まず TLS の終端と証明書の管理です。利用者との HTTPS 接続をエッジで終端するので、証明書の設定と更新を CDN に任せられ、TLS のハンドシェイクも近くで済むぶん速くなります。次にセキュリティで、DDoS攻撃のトラフィックを世界中のエッジで分散して吸収し、WAF(Web アプリケーションファイアウォール)で攻撃のリクエストを入口で弾きます。この意味で CDN は、世界規模に分散した巨大なリバースプロキシだと言えます。

さらに近年は、エッジサーバ上で開発者のコードを実行する「エッジコンピューティング」(Cloudflare Workers、Lambda@Edge など)が広がっています。A/B テストの振り分けや認証の前処理のように、「静的キャッシュでは無理だが、オリジンまで往復するには惜しい」処理を利用者の近くで実行でき、サーバレスの実行基盤としても存在感を増しています。SSG で生成した静的サイトを CDN から丸ごと配る構成は、この流れの代表的な成功例です。

試問

北米にあるオリジン(元のサーバー)のページ /news.html を、北米・欧州・アジアの利用者が取りに来ています。「エッジ」のチップを地域の点線の枠へ運ぶと、その地域に中継サーバーが立ち、ページのコピーを max-age=300 のあいだ手元に置いて配ります。ボタンでオリジンのページを新しい版に更新したり、エッジのコピーを消したり(パージ)できます。

✦ 命題挑戦中

3地域にエッジを置いてからオリジンを更新し、古い版が配られるのを見届けたうえで、全地域の利用者に最新の版を届けよ

  • 3地域すべてにエッジを置く
  • オリジンを更新し、エッジが古い版を配るのを見る
  • そのあと、3地域すべての利用者にエッジ経由で最新の版を届ける
⚡ 体験: エッジを置いて、どこで折り返すかを見る
北米欧州アジア大陸をまたぐ長い道(往復 150〜260ms)オリジンv1/news.htmlmax-age=300押すと止まるエッジの置き場エッジの置き場エッジの置き場———地域の点線の枠へドラッグ(タップでも置ける)エッジ
エッジのヒット率—オリジンまで行った割合—平均応答—
リクエスト応答(v は版)朱の破線の輪=古い版・朱の粒=失敗エッジで折り返す短い道

「エッジ」のチップを地域の点線の枠へ運んで置いてください(タップでも置けます)。いまはすべての利用者が北米のオリジンまで直行していて、アジアからは往復で約 276ms かかっています。