書籍概要

Web配信の技術
HTTPキャッシュ・リバースプロキシ・CDNを活用する

著者
発売日
更新日

概要

HTTPキャッシュ,リバースプロキシ,CDNなどWeb開発で大切な「配信」の技術。
重要な技術ながら,現場では知見のあるエンジニアが少なく,なんとなくで運用されていたり,導入が遅れていたりします。
本書では,HTTPキャッシュの基礎から解説し,一冊でしっかり配信が学べます。

速くて落ちないWebサイト/Webサービス/Web APIの実現はもちろん。キャッシュ事故やセキュリティ上の問題を防ぐのにも役立ちます。

こんな方におすすめ

  • CDNやリバースプロキシの導入に興味のあるアプリケーションエンジニア・インフラエンジニア
  • 配信技術を学びたいインフラエンジニア
  • Webサービスを高速化させたいフロントエンドエンジニア

サンプル

目次

第1章 はじめに

  • 1.1 本書の対象と目的
  • 1.2 本書の構成
  • 1.3 下準備

第2章 配信の基礎

  • 2.1 配信のとらえ方
    • 2.1.1 配信の根幹
  • 2.2 標準仕様でやりとりする
    • Column RFCのMUST/SHOULD―RFC 2119
    • 2.2.1 配信の原則
  • 2.3 配信の経路
    • 2.3.1 ブラウザでWebページを表示するまで
    • 2.3.2 インターネットアクセス時の経路を体験する
    • Column tracerouteで前後するRTT
    • Column 帯域・通信速度・レイテンシ
    • Column 帯域と通信速度の違いを理解する
    • Column プロトコルによるレイテンシへの影響
    • Column 5Gはどこを高速化するのか
  • 2.4 配信をより高速なものにするために
    • 2.4.1 配信最適化のためになにができるのか
    • 2.4.2 配信経路の最適化
    • 2.4.3 クライアントとサーバーでの最適化
    • Column Webサイトのチューニング
  • 2.5 キャッシュの格納場所による分類
    • 2.5.1 クライアントのローカルキャッシュ
    • 2.5.2 経路上のキャッシュ
    • Column CDNの割り振りのしくみ
    • Column EDNS Client Subnet(ECS)―RFC 7871
    • 2.5.3 ゲートウェイ(サーバー/オリジン側)のキャッシュ
  • 2.6 private/sharedキャッシュ
    • 2.6.1 キャッシュの位置とprivate/shared
    • 2.6.2 private/sharedキャッシュの注意点
  • 2.7 どこでどうキャッシュすべきか
    • 2.7.1 キャッシュは誰が管理しているのか
    • Column CDNとゲートウェイキャッシュの違い

第3章 HTTPヘッダ・設定とコンテンツの見直し

  • 3.1 HTTPヘッダの重要性
    • 3.1.1 実際のサイトのヘッダを見る
    • 3.1.2 ヘッダとどう付き合うべきか
    • Column Apacheでのヘッダ操作
  • 3.2 HTTPメッセージ
    • 3.2.1 開始行―RFC 7230\#3.1
    • 3.2.2 ヘッダ―RFC 7230\#3.2
    • 3.2.3 ボディ―RFC 7230\#3.3
    • 3.2.4 HTTP/2でのHTTPメッセージ
  • 3.3 ステータスコードと説明句―RFC 7231\#6
    • Column 暫定応答の1xxと最終応答の1xx以外
    • 3.3.1 代表的なステータスコード
    • Column Status Code 418
  • 3.4 HTTPとキャッシュ
    • 3.4.1 キャッシュを行う・使う条件
  • 3.5 Cache-Controlによるキャッシュ管理
    • Column リクエスト時にもCache-Controlは送信される
    • 3.5.1 キャッシュの保存方法を指定(未指定/public/private)
    • Column キャッシュの仕様改定
    • 3.5.2 キャッシュの使われ方を指定する(no-store, no-cache)
    • 3.5.3 キャッシュの更新の方法を指定する(must-revalidate, proxy-revalidate, immutable)
    • 3.5.4 オブジェクトの取り扱いを指定する(no-transform)
    • Column 中間でのデータ変更(データセーバー・通信の最適化)
  • 3.6 Cache-Controlにおける期限指定
    • 3.6.1 キャッシュの期限と状態
    • 3.6.2 キャッシュは指定した期間保存されるとも限らない
    • 3.6.3 期限が切れたからといってすぐに消されない
    • 3.6.4 キャッシュの期限指定(max-age)
    • 3.6.5 経路上の期限指定(s-maxage)
    • 3.6.6 Staleキャッシュの利用方法を指定する(stale-while-revalidate/stale-if-error)
  • 3.7 Cache-ControlとExpiresヘッダ
  • 3.8 TTLが未定義時の挙動―RFC 7234\# 4.2.2
  • 3.9 キャッシュをさせたくない場合のCache-Control
    • Column 誤ったmax-ageの指定
    • Column キャッシュ不可なステータスコードをキャッシュする
    • Column 仕様はすべて実装されているとは限らない
  • 3.10 さまざまなリクエスト
    • 3.10.1 部分取得リクエスト(Range)―RFC 7233
    • 3.10.2 条件付きリクエスト(If-Modified-Sice/If-None-Match)―RFC 7232
  • 3.11 さまざまなヘッダ
    • 3.11.1 Vary―RFC 7234\#4.1
    • 3.11.2 Content-Type
    • Column 拡張子とMIMEタイプ
    • Column HTTP/2は使わなくてはいけないのか
    • Column HTTPのセマンティクスとRFC
    • Column HTTPを使う上でのベストプラクティスを紹介するRFC
  • 3.12 HTTPヘッダの不適切な設定で起きた事例
    • 3.12.1 Cache-Controlが未定義
    • 3.12.2 コンテンツが更新されてないにもかかわらずETagが変わる
    • Column ロードバランサーとロードバランシング
  • 3.13 ヘッダクレンジング
    • 3.13.1 ゲートウェイとオリジンサーバーを把握する
    • 3.13.2 どのようにコントロールするのか
  • 3.14 コンテンツのサイズ削減
    • 3.14.1 テキストが圧縮転送されていない
    • Column どこで圧縮するべきか
    • 3.14.2 ストレージサービスの圧縮漏れ
    • Column 圧縮は万能ではない
  • 3.15 適切なメディアの選択によるコンテンツの改善
    • 3.15.1 配信システムとファイルサイズ
    • 3.15.2 画像サイズが必要以上に大きくないか(サムネイル)
    • 3.15.3 bppを考える
    • 3.15.4 画像フォーマットは適切か
    • Column WebPと画像サイズ削減
    • Column JPEG画像の注意点
    • Column 外部サービスという選択肢
  • 3.16 問題点を調査する
    • 3.16.1 圧縮転送が有効になっていない
    • 3.16.2 ETag/Last-Modifiedがおかしい
    • 3.16.3 画像コンテンツが大きい
    • 3.16.4 キャッシュが有効に使われていない

第4章 キャッシュによる負荷対策

  • 4.1 キャッシュの構成・設定例
  • 4.2 さまざまな負荷とその事例
  • 4.3 負荷をさばくこととキャッシュ
    • 4.3.1 キャッシュ導入でどの程度パフォーマンスが向上したか
  • 4.4 キャッシュを使わない場合どうさばくか
  • 4.5 キャッシュを使う
    • Column ProxyやCDNはなぜ大量のリクエストをさばけるのか
    • 4.5.1 流入が増えるケースを追って考える
    • 4.5.2 キャッシュの役割
    • 4.5.3 静的ファイルの配信でもキャッシュは有効
  • 4.6 キャッシュ事故を防ぐ
    • 4.6.1 中間(Proxy/CDN)を信頼しすぎる
    • 4.6.2 オリジンを信頼しすぎる
  • 4.7 キャッシュ戦略・キャッシュキー戦略
    • 4.7.1 クライアントからのリクエストを実際に組み合わせる
    • 4.7.2 キャッシュキーとVaryのどちらに設定するか
    • 4.7.3 キャッシュフレンドリなパス設計
    • 4.8 キャッシュのTTLとキャッシュを消す
  • 4.9 キャッシュのTTL計算と再利用―RFC 7234\#4.2
    • Column 生成時刻とTTLを決める際の基準
    • 4.9.1 キャッシュの状態とStale
    • 4.9.2 TTL=0(max-age=0)とは何か
    • Column max-age=0とno-cacheの違い
    • 4.9.3 TTLの決め方
    • 4.9.4 もうひとつのキャッシュ エラーキャッシュ
  • 4.10 キャッシュの消去
    • 4.10.1 無効化と削除
    • 4.10.2 キャッシュ消去の注意点
    • 4.10.3 キャッシュ消去にどこまで依存するか
    • 4.10.4 サロゲートキー・キャッシュタグ

第5章 より効果的・大規模な配信とキャッシュ

  • 5.1 ヒット率だけによらない効率的なキャッシュの考え方
    • Column キャッシュアルゴリズム(LRU/LFU)
  • 5.2 どのようにリクエストを処理してレスポンスをするのか
    • 5.2.1 Proxy/CDNの機能を整理する
  • 5.3 RxReq―クライアントからのリクエストを受信する
    • 5.3.1 ACLの処理
    • 5.3.2 キャッシュキーの操作およびVaryで指定されたセカンダリキーに関連するヘッダの操作
    • 5.3.3 リクエストに含まれる情報に対する操作
    • 5.3.4 キャッシュ可否の判定
    • 5.4 Cache lookup―キャッシュヒットの判定を行う
    • 5.5 Wait for cache―キャッシュができるまで待つ
  • 5.6 TxReq―オリジンにリクエストを送信する
    • 5.6.1 複数のオリジンがある場合の選択
    • 5.6.2 キャッシュキーに影響を与えないオリジン問い合わせ時のホスト名・パス変更
    • 5.6.3 イベントの呼び出し数を減らしたい場合のヘッダ操作
  • 5.7 RxResp―オリジンからレスポンスを受信する
    • 5.7.1 キャッシュ可否の判定(2回目)
    • 5.7.2 TTLを設定する
    • 5.7.3 キャッシュするオブジェクトに対する操作
    • 5.7.4 キャッシュヒット判定に関係するVaryヘッダの変更
  • 5.8 TxResp―クライアントにレスポンスを送信する
    • 5.8.1 キャッシュは変わらないがクライアントごとにヘッダを変える必要がある(CORSなど)
    • 5.8.2 不要なヘッダの編集
  • 5.9 キャッシュキーをVaryで代用する
    • 5.9.1 Varyの利用例
    • 5.9.2 クライアントからの情報でセカンダリキー設定(RxReq)
    • 5.9.3 パスを変更する(TxReq)
    • 5.9.4 キャッシュに格納されるVaryを変更する(RxResp)
    • 5.9.5 クライアントに送るVaryに変更する(TxResp)
    • 5.9.6 Varyもキャッシュキーも編集できないときのクエリ文字列
    • 5.9.7 同一URLで複数のキャッシュを持つ方法の比較
  • 5.10 効果を高める対策
    • 5.10.1 ヒット率を上げる
    • Column 意図せず入るVary
    • 5.10.2 キャッシュするものを適切に選ぶ
    • 5.10.3 ローカルキャッシュがある状態で即時のコンテンツ更新(Cache Busting/no-cache)
    • 5.10.4 操作する場所を意識する
  • 5.11 動的コンテンツのキャッシュ
    • 5.11.1 動的コンテンツとは何か
    • 5.11.2 静的コンテンツ
    • 5.11.3 動的コンテンツ
    • 5.11.4 なぜ明確にTTLが決められないのか
  • 5.12 分割してキャッシュする
    • 5.12.1 キャッシュできるものとできないものを混ぜない
    • 5.12.2 異なるライフサイクルのものはなるべく混ぜない
    • 5.12.3 分離が困難だがとにかくキャッシュがしたい
    • 5.12.4 APIなどコードで生成されたコンテンツのキャッシュ
  • 5.13 Edge Side Includes(ESI)
    • 5.13.1 ESIのメリット
    • 5.13.2 ESIのしくみ
    • 5.13.3 ESIのデメリット
    • 5.13.4 応用的な使い方
  • 5.14 配信構成の工夫
    • 5.14.1 ストレージ
    • 5.14.2 Proxyの増設(スケールアウト)
  • 5.15 多段Proxy
    • 5.15.1 Proxyを増設すると何が起きるのか
    • 5.15.2 多段Proxyのメリット―一貫性
    • 5.15.3 1段方式の多段Proxy
    • 5.15.4 2段方式の多段Proxy
    • Column ハッシュをとってどのように振り分けを行うか
    • 5.15.5 どの方式の多段Proxyを採用すべきか
    • 5.15.6 多段Proxyのメリットをより深く理解する
    • 5.15.7 多段Proxyの注意点
    • Column キャッシュ巻き戻りの問題
    • Column max-ageが変動する時の注意
  • 5.16 障害時に正しくサーバーを切り離す(ヘルスチェック)
    • 5.16.1 ヘルスチェックを行う側の設定
    • 5.16.2 ヘルスチェックを受ける側の設定
  • 5.17 ドメインの分割
    • 5.17.1 動的コンテンツと静的コンテンツでドメインを分ける
    • 5.17.2 ZoneApex問題への対策

第6章 CDNを活用する

  • 6.1 なぜCDNが必要なのか―自前主義だけだと難しい
    • 6.1.1 自前主義がもたらす高コストとCDN
    • 6.1.2 CDN + 自社配信という選択肢
  • 6.2 CDNを使う前に
    • 6.2.1 CDNとは
    • Column オブジェクトストレージとCDN
    • 6.2.2 CDNだからできること
    • Column コラム ネットワークの品質が良いということはどういうことか
  • 6.3 CDNの選び方
    • 6.3.1 代表的なCDNの一覧
    • 6.3.2 どの地域に配信をするのか(海外・国内配信)
    • 6.3.3 ピーク帯域がどの程度あるのか CDNが対応できるか
    • 6.3.4 どのようにキャッシュを制御するのか
    • 6.3.5 HTTPSの取り扱い
    • 6.3.6 CDNのキャッシュの消去
    • 6.3.7 Apexドメインの扱い
    • 6.3.8 信頼できるのか
    • 6.3.9 CDNの多段キャッシュ
    • Column コンテンツの一貫性はどれほど必要なのか
  • 6.4 CDNを使うときに気をつけたいポイント
    • 6.4.1 キャッシュされない設定を調べる
    • 6.4.2 クエリ文字列の解釈について
    • 6.4.3 トラフィックなどの制限に注意
    • 6.4.4 コンテンツのサイズに注意
    • 6.4.5 Varyに注意
    • Column キャッシュ汚染DoS(CPDoS)
    • 6.4.6 CDNのデバッグ
    • Column CDNのヘッダと標準化
    • 6.4.7 CDNで隠したい情報をきちんと整理する
    • 6.4.8 ウォームアップ
  • 6.5 クライアントの近くでコードを動かす - エッジコンピューティング
    • Column 内部向けにCDNを使う - internal CDN
    • Column CDNのコスト
  • 6.6 CDNと障害
    • 6.6.1 CDNの障害
    • 6.6.2 問題の切り分け―それはCDNの障害なのか
    • 6.6.3 まずはmetricsを見てみる
    • 6.6.4 CDNの典型的な障害
    • 6.6.5 コンテンツのダウンロードが遅い
    • 6.6.6 キャッシュが壊れる
  • 6.7 動的コンテンツのキャッシュやCDN利用は危険なのか
    • Column マルチCDN
    • Column DNSブロッキングにかかる
    • Column 適切に設定しているのにキャッシュされない
  • 6.8 実際にCDNを設定する
    • 6.8.1 動的コンテンツの設定例

第7章 自作CDN(DIY-CDN)

  • 7.1 なぜCDNをつくるのか
    • 7.1.1 低予算
    • 7.1.2 ハイブリッドで使う
    • Column CDN自体を多段で使うときの注意
  • 7.2 低予算自作CDNの構成
    • 7.2.1 さまざまなことを諦める
    • 7.2.2 基本構成
    • Column VPSのプランをどう選ぶか
  • 7.3 自作CDNと外部CDNのハイブリッド構成
    • Column 低コスト運用からその先へ
  • 7.4 VCLでの設定例
    • 7.4.1 gatewayとcacheでの設定の目的
    • 7.4.2 リクエストの正規化
    • 7.4.3 キャッシュする場合のCookieなどの取り扱い
    • 7.4.4 TTLの設定
    • 7.4.5 オリジンへの振り分け
    • 7.4.6 ストレージの分割
    • 7.4.7 オリジンでの注意
    • 7.4.8 VCLサンプル

Appendix Varnishについて

  • A.1 Varnishのインストール
  • A.2 読みたい公式ドキュメント
  • A.3 Varnishのサポート体制
  • A.4 基本的なVCL
    • A.4.1 Varnishの起動方法と最小のVCLと考え方の基礎
    • A.4.2 文法の初歩
    • A.4.3 backendとdirector
    • A.4.4 サブルーチンとVCL変数
    • A.4.5 条件分岐・演算子・正規表現
    • A.4.6 VCLのデータ型と型変換
    • A.4.7 VCLを学ぶ
  • A.5 VCLを記述する際の注意点
    • A.5.1 "を含む文字列の指定方法
    • A.5.2 正規表現の取り扱い
    • A.5.3 デフォルトのVCLと同一名のVCLイベントの定義
    • A.5.4 VMOD
    • A.5.5 折り畳みをしてはいけないヘッダの扱い
  • A.6 テストの重要性―varnishtest
  • A.7 varnishのログと絞り込み方
    • A.7.1 VSLのグループ化
    • A.7.2 ログの絞り込み
  • A.8 そのほかのツールやコマンド
    • A.8.1 varnishstat
    • A.8.2 varnishadm
    • A.8.3 varnishtop
    • Column graceとkeepの取り扱い
    • Column VarnishとHTTPS

サポート

ダウンロード

サンプルファイルのダウンロード

(2021年2月2日更新)

本書のサンプルファイルをご利用いただけます。

ダウンロード
サンプルファイル

正誤表

本書の以下の部分に誤りがありました。ここに訂正するとともに,ご迷惑をおかけしたことを深くお詫び申し上げます。

(2022年4月19日最終更新)

P.2 1.1の説明文中の記述

スマーフォン
スマーフォン

P.3 1.1のサーバーのリクエストに関する文言

クライアント(閲覧者)が増えればサーバーへのリクエスト増えていきます。
クライアント(閲覧者)が増えればサーバーへのリクエスト増えていきます。

P.4 1.1の図1.4下の説明

ProxyやCDNがキャッシュとクライアントの間に入り、代わりに
ProxyやCDNがサーバーとクライアントの間に入り、代わりに

(以下2021年4月5日更新)

P.11 2.1の脚注2

VTuebr
VTuber

P.88 3.5.2のno-cacheに関する説明文

仕様上no-cacheは引数を持つことがありますが、実用されておらず、筆者は見かけたことはありません。
仕様上、no-cacheは引数を持つことがあります。ただし、筆者の知る限りでは実装はほとんどありません。

P.100 3.10.2の見出しの文言

条件付きリクエスト(If-Modified-Sice/If-None-Match)―RFC 7232
条件付きリクエスト(If-Modified-Since/If-None-Match)―RFC 7232

P.208 第5章のコラム「キャッシュアルゴリズム」内のLFRUの表記

LFRU(Least frequent recently used)などもあります。
LFRU(Least Frequently Recently Used)などもあります。

P.252 5.12.4の識別子の説明

その際にEtagや
その際にETag

P.284 5.16.2の静的ファイルでのチェック箇所

LProxy←→App間のネットワーク
Appのネットワークの状態
Proxy←→Appサーバー間のネットワーク
Appサーバーのネットワークの状態

P.304 第6章のコラム「ネットワークの品質が良いということはどういうことか」の見出し文言

コラム ネットワークの品質が良いということはどういうことか
ネットワークの品質が良いということはどういうことか

本来は不要な「コラム」の文字が入っていました。

P414 A.5.1のエスケープの説明

ところが、VCLでは「」でのエスケープには対応していないため通りません。
ところが、VCLでは「\」でのエスケープには対応していないため通りません。

P.418 A.6の脚注47のドキュメントのURL

https://github.com/varnish/varnish-modules/blob/master/src/vmod_header.vcc
https://github.com/varnish/varnish-modules/blob/0.17.0/src/vmod_header.vcc

URL中のバージョン指定が一部誤っていました。

補足情報

7章のCloudflareに関する情報について

(2023年5月26日更新)

Cloudflareの無料プランでは多段構成はできません。ヒット率を稼ぐためにも自社配信での多段構成は必須です。

https://blog.cloudflare.com/orpheus/

Cloudflareの多段構成(Tiered Caching)は元々有料機能でしたが,2021/09に無料で開放されました。有用な機能ですので有効にするのをお勧めします。

また,サイトのドメインとは別にCDN用のドメイン切り出して運用することを例としておりますが
https://www.cloudflare.com/service-specific-terms-application-services/
こちらの「Content Delivery Network (Free, Pro, or Business)」で触れられているようにあくまでもWebページ・サイトをキャッシュして利用することを想定しています。

そのため,恒久的にCloudflareを使う場合は,サイト側もCloudflareを通す必要があります。

(以下2021年4月21日更新)

P.69 3.3.1 代表的なステータスコード中の308に関する補足

リダイレクトで利用するステータス308はRFC7538で定義されています。

P.88 3.5.2のno-cacheに関する説明文の補足

書籍中ではほとんどない,見かけたことがないとしたno-cacheの引数について補足します。

CloudFrontはno-cache="param"の記法に対応しています。 https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/Cookies.html を参照してください。

P.94 3.6.5のs-maxageとmaxageの設定に関する言及の補足

3.6.5でs-maxageはmax-ageより小さくすべきと記載しましたが,意図してCDNなどではキャッシュを行いクライアントではキャッシュを行わない場合はs-maxage=3600, max-age=0といった設定をすることがあります。
この効果は「5.10.3 ローカルキャッシュがある状態で即時のコンテンツ更新」で触れたCDNではキャッシュを行いクライアントにはno-cacheを返すときとほぼ同等の効果が得られます。no-cacheだとCDN側でレスポンスヘッダの改変が必要ですが,s-maxage=3600, max-age=0だとCDN側での改変なしでも設定が可能ですので環境に応じて使うのが良いでしょう。

P.333 6.6.4で紹介したWeb are socialのレポートに関する補足

We are socialのレポートは毎年更新されており,2021年版によると平均ダウンロード速度は固定回線が96.43Mbpsでモバイルが42.70Mbpsと書籍中で触れた2019年当時のデータ(固定54.3Mbps/モバイル25.1Mbps)よりかなり向上しています。

商品一覧