Skip to content

MS_HTTP2

nishi_74322014 edited this page Aug 3, 2026 · 1 revision

HTTP/2について調べてみた。

概要

gRPC を調べようと思っていたら、HTTP/2 なるキーワードが。
「そういや話題になっていたなぁ。」などと思い少々調査してみました。

HTTP/2とは

  • 2015 年 2 月 17 日に正式な仕様として承認
  • 2015 年 5 月に RFC 7540 として文書化
  • HTTP/1.1 が 1999 年 6 月に RFC 2616 として
    規定されて以来 16 年ぶりのバージョンアップ。

補足(最新化): RFC 7540 は 2022 年に RFC 9113 で置き換えられた。 同時に HTTP のセマンティクス自体も整理され、 RFC 2616 → RFC 723x → RFC 9110(HTTP Semantics)/ 9111(Caching)/ 9112(HTTP/1.1) という構成になっている。 現行の参照先は RFC 9110 番台である。

経緯

  • 米 Google による Web 高速化の「SPDY」プロトコルが生み出された。
  • 有名サイトも次々と「SPDY」を取り入れるようになった。
  • 標準化団体 IETF によって標準化が進められ、RFC 化した。

目的

HTTP の高速化。

方法

ストリームという仕組みを使用する。

プロトコル

  • 既存の HTTP と互換性を保ちながらセッション層を効率化する。
  • そのため、HTTP の表面上の機能はそのままに、内部動作だけを置き換える。

今後

  • まだ、十分な実績がないので、検証中のプロトコル。

    • HTTP/1.1 に置き換わるのか?
    • 一部の仕様だけが生き残るのか?
  • HTTP/2 は TCP/IP 上で動作するため、品質の低い回線上で実行した場合、
    パケット遅延、パケットロスなどで全体遅延になる問題がある。

    • このため、米 Google は「QUIC」という UDP 上で HTTP を処理する
      新しいプロトコルを開発中である。
    • 「QUIC」も「SPDY」と同様に、IETF を通じた標準化を目指している。

補足(最新化): 執筆時点の「検証中」という評価は、 現在は解消している。HTTP/2 は主要な Web サイトで既定であり、 HTTP/1.1 を置き換えた(ただし完全に消えてはいない)。

また「QUIC を開発中」も実現し、 RFC 9000(QUIC)/ RFC 9114(HTTP/3) として標準化された。 詳細は HTTP/3について調べてみた。 を参照。

一方で、HTTP/2 の機能のうち廃れたものもある。 サーバプッシュは効果が乏しく実装が難しかったため、 Chrome が 2022 年に既定で無効化し、事実上廃止された (代替は 103 Early Hintsrel=preload)。

HTTPの高速化

通信・接続の多重化

  • HTTP では、1 つのリクエストが完了するまで、次のリクエストを送ることができない。
  • 現在、多くのブラウザは 1 ドメインへの接続を同時に複数行い、通信を多重化している。
  • ただし、HTTP/1.1 の仕様としては 2 つまでとされている。

移行メモ(補足): 「2 つまで」は RFC 2616 の SHOULD NOT(推奨) であって、強制ではない。 実際のブラウザはホストあたり 6 本程度を張るのが一般的で、 RFC 7230 ではこの記述自体が削除されている。

HTTPパイプラインとHoL(Head of Line)ブロッキング

  • HTTP パイプライン

    • HTTP/1.1 から、前回リクエストの完了を待たずに次のリクエストを送信可能
    • しかし、実装の困難さから、HTTP パイプラインを正しく実装したサーバが少ない
    • 故に、現在ほとんどのブラウザは HTTP パイプライン機能を全く実装していないか、
      デフォルトでオフ。
  • HoL(Head of Line)ブロッキング

    • HTTP パイプラインには、
      「サーバはリクエストの順番通りにレスポンスを返さなければならない」という制限がある。
    • これは、「先頭のリクエストの処理に時間がかかる場合、
      後続のレスポンスは全てブロックされる」という問題を起こす。

リソース読み込みを速くする様々な工夫

  • リソースの結合

    • CSS や JS ファイルを 1 つに結合するテクニック
    • ASP.NET では Bundle 機能が提供されている。
  • 画像のインライン埋め込み
    HTML 内に base64 でエンコードした画像を直接埋め込む方法

    <img src="data:image/gif;base64,(・・・base64文字列・・・)">
  • ドメインシャーディング

    • 多重化には、前述の制限がある。
    • この制限を掻い潜るためリソースファイルの取得先ドメインを分割する。

補足: これらは HTTP/1.1 時代の回避策であり、 HTTP/2 ではむしろ逆効果になりうる

  • ドメインシャーディング — HTTP/2 は 1 本のコネクションで 多重化するため、ドメインを分けるとコネクションが増えて損になる。
  • リソースの結合 — 1 バイトの変更で巨大なバンドル全体が キャッシュ無効になる。細かく分けたほうがキャッシュ効率が良い。
  • 画像のインライン埋め込み — 個別にキャッシュできなくなる。

HTTP/2 に移行したら、これらの「工夫」は見直すこと。

HTTP/2のストリーム

  • 1 つの TCP/IP コネクション上でリクエスト・レスポンスを並列化する。
  • ストリームの多重化により HoL ブロッキングの問題は解決する。

補足(正誤): 「HoL ブロッキングの問題は解決する」は HTTP レイヤに限った話である。 HTTP/2 は TCP 上で動くため、 TCP レベルの HoL ブロッキングは残る。 パケットが 1 つ落ちると、 その TCP コネクションに相乗りしている全ストリームが待たされる。 この問題を解こうとしたのが、UDP ベースの QUIC= HTTP/3について調べてみた。 である。

フレーム

  • 並列化のためフレーム

    • 各ストリームにおけるメッセージのやり取りはフレームという単位で行う。
    • フレームはバイナリで定義され、各フレームは 9 オクテットのヘッダと、
      可変長のペイロードで構成される。
  • PRIORITY フレーム

    • クライアントが PRIORITY フレームを用いてストリーム間に優先順位を付ける
    • 優先順位付けの方法には、「重み付け」と「依存関係」の 2 つがある。

補足: HTTP/2 の優先度制御(依存ツリー)は複雑すぎて 相互運用が難しく、RFC 9113 で非推奨となった。 代わりに RFC 9218(Extensible Prioritization Scheme)が定義され、 Priority ヘッダで指定する方式に置き換わっている。

ストリームのID

  • ストリームはクライアント、サーバのどちらからでも開始できる。
  • 競合回避のため、
    • クライアント側から開始したストリームには奇数の ID を割り当てる。
    • サーバ側から開始したストリームには偶数の ID を割り当てる。

ウインドウ制御

  • TCP/IP でも実装されているようなウインドウ制御を実装している。
  • HTTP/2 で実装する理由は、
    • TCP/IP コネクションを並列化しているため。
    • 並列化した中の個別のストリームの制御を行う。
    • 例: 動画のストリーミング中に、そのストリームのみ停止する。

ヘッダ圧縮

従来、HTTP のコンテンツボディのみを gzip 圧縮していたが、HTTP/2 では、

  • ストリーム内の HTTPヘッダ も圧縮する。
  • 圧縮には、gzip ではなく、HPACK を使用する。
    CRIME という gzip 圧縮の特性に着目して、
    SSL 暗号を無効化する攻撃手法を回避するため。

サーバプッシュ

サーバ側からクライアントにデータをプッシュできる。

  • 具体的に言えば、リクエストされたページに必要なリソースを
    予めクライアントに送信しておくための仕様と言える。
  • 使用例としては、HTML に関連付けられている CSS や画像などのリソースを、
    クライアントのリクエストを待たずにサーバーからプッシュ送信できる。

補足(最新化): 前述のとおり、サーバプッシュは事実上廃止された。 「クライアントが既に持っているかサーバは知り得ない」ため 無駄な転送が発生しやすく、期待した効果が出なかったためである。

使い方

コンテンツ側

内部動作だけを置き換えるので、コンテンツ側は何もしなくてイイ。

サーバープッシュ

サーバプッシュを使用する場合だけ、コンテンツ側に実装の変更が必要になる。

ASP.NET

  • ASP.NET Web Forms(MS_ASPNETWebForms.md)でサーバープッシュを使用する場合、
    サーバー側で以下のメソッドを実行して予めコンテンツをプッシュしておく。

    Response.PushPromise("~/・・・コンテンツの仮想パス");
  • ASP.NET MVC(MS_ASPNETMVC.md)でサーバープッシュを使用する場合、
    URL ヘルパに拡張メソッドとして実装した例がある。

参考: IIS 10.0 と ASP.NET 4.6 で HTTP/2 のサーバープッシュが使えるようになっていたので試した - しばやん雑記

サポート状況

IIS

IIS というか、http.sys(HTTP カーネル モード ドライバ)で、サポートされている。

補足: IIS で HTTP/2 が有効になる条件は Windows Server 2016 / Windows 10 以降かつ HTTPS 接続である。 HTTP/2 の仕様上は平文(h2c)も定義されているが、 ブラウザは平文の HTTP/2 をサポートしないため、 実質 TLS が必須である。

なお、Windows Server 2016 の IIS では Windows 統合認証(Kerberos / NTLM)を使うと HTTP/1.1 にフォールバックするという制約があった。

.NET

  • .NET 2015(.NET Framework 4.6 および .NET Core)から、サポートされている。
  • 従って、当該バージョン以降の ASP.NET(MS_ASPNET.md)& HTTPClient で使用可能。

補足(最新化): HttpClient で HTTP/2 を使うには、 明示的にバージョンを指定する必要がある。

var req = new HttpRequestMessage(HttpMethod.Get, url)
{
    Version = HttpVersion.Version20,
    VersionPolicy = HttpVersionPolicy.RequestVersionOrLower
};

.NET Core 3.0 以降では SocketsHttpHandler が既定で HTTP/2 に対応している。

その他

  • サーバー: IIS, Apache, nginx 等の主要なサーバーで、サポートされている。
  • クライアント: 主要なブラウザで、HTTP/2 over TLS でサポートされている。

参考


Tags: IT国際標準, 通信技術, IIS, .NET開発, .NET Core, ASP.NET, ASP.NET MVC

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally