HTTP/1.1→2→3 — 多重化への道
HTTPの30年は「1本の接続で何件同時に喋れるか」を巡る改良の歴史です。1.1の一問一答がなぜ渋滞を生んだか、2がフレームとストリームで何を解き、その詰まりがなぜ下の階へ移っただけだったか、3がQUICで何を分離したか。そして自分の環境でどう測って選ぶかまでを、前提知識ゼロから積み上げます。
一問一答という約束が、渋滞を生んだ
HTTPは驚くほど単純な取り決めです。要求を送ると応答が返る。それだけで30年生き延びました。ただし条件が1つ付いています。1本の接続の上では、1つの応答が終わるまで次の応答を始められない。
窓口が1つしかない役所を想像してください。前の人の手続きが終わるまで次の人は呼ばれず、用事が10件あれば10回並び直すことになります。
HTTP/1.0は文字通り並び直していました。要求のたびに接続を張り、応答を受け取ったら切る。HTTP/1.1は keep-alive で接続を使い回し、Host ヘッダや chunked 転送も足します。大きな改善でしたが、一問一答という条件だけは残りました。
抜け道も用意されてはいました。応答を待たずに次の要求を送るパイプライニングです。ただし応答は要求された順に返さなければならないという縛りが付きます。1番目が重いAPI、2番目が小さな画像なら、画像は先に用意できていても出せません。先頭が詰まると後ろが全部待つ、これがHead-of-Lineブロッキング(HOLブロッキング)です。中間装置の実装差で壊れるサイトも多く、主要ブラウザは既定で無効にしました。
ブラウザが編み出した力技と、その請求書
接続1本で足りないなら増やせばいい。ブラウザは同一オリジンあたり6本前後を並列に張るようになりました。かかる時間はおおよそこうなります。
は取ってくる部品の数、 は同時に張れる接続の数、 は1往復にかかる時間です。要するに、部品が増えれば時間もそのぶん比例して増える。1ページに画像やスクリプトが100個載る時代には致命的でした。
そこで現場は を減らしにかかります。画像を1枚に貼り合わせるCSSスプライト、JSやCSSのバンドル、data URIでの直接埋め込み。 を増やす方の力技がドメインシャーディングで、静的資産を img1 img2 に分散させて6本×ドメイン数まで稼ぎました。
しかし接続はタダではありません。1本ごとにTCPとTLSの握手が要り、輻輳ウィンドウ(一度に送り出してよい量の見積もり)はゼロから育て直しです。6本張れば6本とも「まだ遅い状態」から始まり、そのうえ同じ帯域を奪い合います。
HTTP/2 — 1本の管の中に、複数の流れを彫る
2015年のHTTP/2(現行はRFC 9113)は構図を作り直しました。単位は3つです。フレームは通信の最小単位で、種別・長さ・所属するストリームIDを持つ小さな塊。ストリームは1回のやりとり(1リクエストと1レスポンスの組)に対応する番号付きの仮想通路。接続はTCP接続1本で、この中に何百ものストリームが同居します。
決定的なのは、フレームがストリームIDを持っている点です。ある応答を送りきらないうちに別ストリームのデータを差し込んでよく、受け手はIDを見て仕分けるだけ。順序の縛りが消え、6本でやっていたことが1本で足ります。改行区切りのテキストをやめてバイナリのフレーム形式にしたのは、この仕分けを機械が安く正確にやるためです。
コメント
コメントにはログインが必要です