目次


HTTP/2 の内幕

HTTP/2 のリクエスト/レスポンスの多重化、ヘッダー圧縮、サーバー・プッシュによって、Web サイトのパフォーマンスが向上する仕組み

Comments

HTTP/2 で最優先されている目標は、Web アプリケーション・ユーザーのエクスペリエンスを改善することです。バイナリー・プロトコルである HTTP/2 は、軽量、セキュア、高速というバイナリーならではのメリットのすべてを兼ね備えています。HTTP/2 は元の HTTP プロトコルのセマンティクスを維持していますが、システム間でのデータ転送方法については変更しています。ただし、データ転送の複雑な詳細は主にクライアントとサーバーによって管理されるので、大幅な変更を加えなくても Web サイトおよびアプリケーションで HTTP/2 のメリットを利用することができます。

この記事では HTTP/2 の概要について、このプロトコルが解決しようとしている問題ならびにパフォーマンスを向上させるさまざまな機能 (リクエスト/レスポンスの多重化、ヘッダー圧縮、サーバー・プッシュなど) を含めて説明します。

HTTP の歴史

HTTP/2 プロトコルの詳細を探る前に、時間を遡って HTTP でのその源流を見ていきましょう。

HTTP が初めて公になったのは、HTTP 0.9 仕様として形になった 1989 年のことです。当時、スイス・ジュネーブ近くの CERN で Sir Timothy Berners-Lee 氏が初期設計を行った HTTP 0.9 はたった 1 行で作成されていました。その当時は GET が唯一のメソッドであり、リクエストは GET /index.html といった実に単純な形です。レスポンスも同じく単純で、リクエストされたファイルだけを格納していました。

HTTP 0.9 は公式の仕様ではないため、以降に続く公式バージョンは、これを区別するために、このバージョン番号を含めた名称で呼ばれるようになりました。公式バージョンである HTTP 1.0 は、1996 年に IEFT 標準の RFC 1945 として公開されました。その後、1999 年に HTTP 1.1 が RFC 2616 として公開されるまでには、かなりの間が空いています。1999 年のこのマイナー・リビジョンには、最初のメジャー・リリースに伴う欠点を補うことを目的に、任意で使用できる多数の機能と細々とした詳細が導入されていましたが、問題はそこにありました。

HTTP 1.1 のあらゆる側面を採り入れたブラウザー (またはサーバー) 実装はほぼゼロに近かったことから、ブラウザーの間でユーザー・エクスペリエンスに不整合が生じてきたのです。とりわけ、HTTP 1.1 で導入された HTTP パイプラインのパフォーマンス強化機能の実装には、ほとんどのブラウザー・ベンダーが失敗しました。

Web が普遍的に使用されるようになる中、パフォーマンスに対するニーズが急激に高まり、それと同時に HTTP に対する要求も大幅に増してきました。このプロトコルの欠点をどうにか克服するために、開発者たちはハックを作成するようになりました。例えば、HTTP での非効率的な TCP ソケットの使用法がパフォーマンスの妨げとなっていたことから、開発者は複数のサーバーを複雑に組み合わせてアプリケーションの需要を満たすという手段に頼るようになりました。このように、パイプラインを適切に機能させられなかったという事実が、HTTP を大々的に見直す必要性に拍車をかけたのです。

15 年以上の歳月が過ぎた末にようやく、HTTPbis ワーキング・グループが召集されました。このプロトコルで解決できない問題を公式に特定し、最終的には HTTP/2 に期待する内容をドラフトとしてまとめるためです。エンド・ユーザーが認知する HTTP 1.1 の待ち時間を大幅に改善するという任務を負ったワーキング・グループが作成したプロトコル案は、「ヘッド・オブ・ライン・ブロッキング」問題に対する解決策と、ヘッダー圧縮、そしてサーバー・プッシュを特徴としていました。RFC 7540 (HTTP/2) は 7541 (HPACK) と併せて、Web アプリケーションのパフォーマンスに革命的な向上をもたらすことを約束したのです。

現在の HTTP

WWW の誕生以来、Web ページはますます複雑になってきています。初期の頃の Web ページは極めて単純なものであり、テキストだけで構成されていました。つまり、画像も、CSS も、JavaScript も使用されていない、簡素な旧式の HTML だけを使用したページです。現在に目を移すと、平均的な Web ページがダウンロードするリソースの数は 100 を超えていて、そのサイズは約 2,500 KB となっています。転送されるデータの合計サイズは、2012 年 5 月の時点と比べると 250 パーセントも増えており、この増加率が低下する気配はありません。

図 1. データの合計転送サイズ合計リクエスト数 (2012 年~ 2017 年)、出典: HTTPArchive
2012 年から 2017 年までのデータの合計転送サイズ合計リクエスト数の増加を示す図
2012 年から 2017 年までのデータの合計転送サイズ合計リクエスト数の増加を示す図

ハックと次善策

極めて複雑なコンテンツの高速配信にインターネットが対応できるのは事実ですが、HTTP 1.1 プロトコルの短所を克服して実施されています。現在の形では、HTTP が Web エクスペリエンスに対する最近の要求に対処することはできません。そのため、Web 開発者たちはパフォーマンスの問題に対するさまざまな次善策を考案してきました。とりわけよく使われているハックのいくつかと、それらのハックが解決する問題を見ていきましょう。

ヘッド・オブ・ライン・ブロッキング

HTTP 1.0 では、単一の TCP 接続を使用して実行できるリクエストは 1 つに限られていました。このことが原因で、レスポンスが返されるまでブラウザーが長々と待たされるという、いわゆる「ヘッド・オブ・ライン・ブロッキング」問題が生じる結果となりました。HTTP 1.1 でこの問題に対処するために導入したのが、パイプラインという手法です。パイプラインを使用することで、ブラウザーは複数のリクエストを並行して実行できるようになります。けれども、ブラウザー・ベンダーは HTTP パイプラインの実装に苦戦したことから、ほとんどのブラウザー (Firefox を含む) に同梱されている HTTP パイプラインはデフォルトで無効にされています。Chrome に至っては、HTTP パイプラインを完全に削除しています。

複数の TCP 接続

TCP 接続をオープンするのにはコストがかかります。しかも、その接続をクライアントがどのように使うべきかについての情報はほとんどありません。唯一のプロトコル規定として、ホストごとにオープンできる接続は最大 2 つに制限されます。TCP 接続を 2 つしか使用できないことから、開発者たちは、最近の Web ページに必要な多数のリソースを配信するのに苦労していました。この制約を回避するために考え出され、よく使われている手法があります。

ドメイン・シャーディングです。この手法を使用すれば、開発者は複数のホストを作成して、そのそれぞれからサイトで必要となるリソースのサブセットを提供することができます。ドメイン・シャーディング手法が普及した結果、ページのロード時にオープンされる TCP 接続の平均数は約 35 に達するようになりました (出典: HTTPArchive)。

ブラウザー・ベンダーは過剰な接続を防ぐために、許容する追加のオープン接続の数をブラウザーの実装で任意に制限して、このプロトコルを拒否するようになりました。この対策は、個々のブラウザー内でリソースのロードを並列化する上では役立ちますが、TCP ソケットを非効率的に使用することになります。以下の表に、ホスト名あたりに許可される最大オープン・ポート数を示します。上位 3 つのブラウザー間での TCP 接続数の違いがわかります。

表 1. 同時にオープン可能な最大 TCP 接続数 (出典: browserscope.org)
ブラウザーホスト名あたりの最大同時接続数
Chrome24
Firefox6
Internet Explorer 1211

ブラウザー実装によって最大同時接続数に違いがあるということは、Web サーフィンでのユーザー・エクスペリエンスの品質は、サイトの設計と構成の良し悪しではなく、どのブラウザーを選択するかによって左右されることを意味します。

リソースのインライン化と連結

Web アプリケーション開発者がパフォーマンスを向上させるために使用している巧妙な手法は、ドメイン・シャーディングだけではありません。他にも以下の手法があります。

  • ファイル連結。ファイルを連結して、必要なリソースのすべてを含めた 1 つの大容量ファイルにします。サイトのすべての CSS に対して 1 つ、JavaScript に対して 1 つ、そしてサイトのアイコンを格納する画像スプライト・シートに対して 1 つのファイルを作成します。
  • リソース・インライン化。CSS と JavaScript を直接 HTML に埋め込みます。これにより、HTML に画像を埋め込むことも可能になります。画像は base64 でエンコードし、Web ページをロードする際にデコードします。

以上の手法は、いずれも望ましいものではありません。特に設計の観点からすると、避けるべきです。どちらの手法にしても、ページの構造がスタイルと混合されるだけでなく、画像のデコードに時間がとられることになるからです。また、キャッシングについても簡単には実現できなくなります

ただし、リクエストするファイルの数を減らすことだけが目標だとしたら、これらの次善策でその目標を達成できます。また、ファイルのリクエスト数が少なくなれば、必要なオープン TCP ソケットの数も少なくなります。

注目すべき特徴

HTTP/2 で功を奏している機能の大部分は、Google が SPDY プロトコル上で開始した取り組みのおかげで実現したものです。HTTPbis ワーキング・グループが HTTP/2 RFC の最初のバージョンをドラフトとして作成し始めるまでには、すでに SPDY によって、HTTP のメジャー・バージョンは更新すべきであることが証明されていました。SPDY がデプロイされて採用され始めていたことが、SPDY という更新されたプロトコルのほうが実際のインターネットでパフォーマンスが向上するという証拠となったのです。

HTTP/2 の成功には、HTTP パラダイムならびに HTTP と HTTPS のスキーマを維持しつつ、パフォーマンスを大幅に向上させることが不可欠でした。ワーキング・グループは、HTTP/2 への移行を透過的にすることを要件とし、エンド・ユーザーが移行による混乱を被らないよう取り決めました。

HTTP/2 プロトコルには、以下の注目すべき特徴があります。

  • 新しいアップグレード・パス
  • バイナリー・フレーミング
  • リクエスト/レスポンスの多重化
  • ヘッダー圧縮
  • ストリームの優先度
  • サーバー・プッシュ
  • フロー制御

以上の特徴のそれぞれを見ていきましょう。

新しいアップグレード・パス

HTTP/2 のアップグレード・パスは通常とは少々異なり、一部のネゴシエーションを省いています。アップグレード・ヘッダーを介してプロトコル切り替えをリクエストし、切り替えを保証する「101 switching」HTTP ステータスを受け取るという方法は、HTTP/2 によるセキュアな接続には使用できません。クライアントは ALPN (Application Layer Protocol Negotiation) と呼ばれる新しい拡張機能を使用して、クライアント自体が把握する通信プロトコルを優先する順に並べてサーバーに通知します。サーバーは、そのリストに含まれるプロトコルのうち、サーバー自体が把握する最初のプロトコルを使用してレスポンスを返します。

SPDY はセキュアな接続を要件としている一方、HTTP/2 仕様ではコミュニティーからの圧力があったにもかかわらずセキュアな接続を要件としていません。主要なブラウザー・ベンダーのすべてが実装しているのは HTTP/2 over TLS のみで、非セキュアな接続をサポートしていません。このことから、事実上、Web アプリケーションの実装者はあらゆる HTTP/2 トラフィックに TLS を使わざるを得ません (出典: caniuse.com)。ただし、curl ユーザーは引き続き HTTP アップグレード・ヘッダーによるアップグレード・パスを使用できます。curl は、非セキュアな接続とセキュアな接続の両方を実装するためです。

バイナリー・プロトコル

HTTP/2 での最も重要な変更は、おそらくバイナリー・プロトコルへの転換でしょう。開発者にとってこの転換は、ほぼ間違いなく、パフォーマンス向上の源となっています。バイナリー・フレーミング・レイヤーと呼ばれる新しいプロトコルでは、慣れ親しまれているメソッド、動詞、ヘッダーのセマンティクスを変更せずにエンコーディング・メカニズムを設計し直しています。

最も重要な点は、すべての通信が、その全体を通してオープン状態に維持される単一の TCP 接続で行われることです。これを実現しているのは、このバイナリー・プロトコルが通信をフレーム単位に分割する仕組みです。これらのフレームが、クライアントとサーバー間の双方向の論理ストリーム内でインターリーブされるのです。

接続のトポロジー

HTTP/2 の新しいパラダイムでは、上述したように、クライアントとサーバーの間に単一の TCP 接続が確立され、クライアントとサーバーがやりとりする間、その接続がオープン状態に維持されます。オープン状態が維持された接続で、論理ストリームを使用してメッセージが渡されます。メッセージは、フレームの完全な配列からなります。これらのフレームを順に並べると、レスポンスまたはリクエストという形になります。

図 2 に、接続コンポーネントの相互関係を示します。図中では、この単一の接続を通じて複数のストリームが確立されています。ストリーム 1 内で、リクエストが送信されて、そのリクエストに対するレスポンスが返されます。

図 2. HTTP/2 接続のトポロジー
HTTP/2 接続のトポロジーを示す図
HTTP/2 接続のトポロジーを示す図

ここからは、これらの概念について個々に取り上げていきます。

接続とストリーム

ピアとの間で単一の接続が確立され、その接続を介して複数のストリームが送信されます。ストリームはインターリーブできるようになっていることから、単一の接続で複数のストリームを同時に送信できます。

メッセージ

メッセージは、フレームの集合です。これらのフレームは、ピアにて再アセンブルされると完全なリクエストまたはレスポンスという形になります。ある特定のメッセージを構成するフレームは、すべて同じストリームを介して送信されます。つまり、リクエストまたはレスポンスは、単一の識別可能なストリームにマッピングできるということです。

フレーム

通信の基本単位はフレームです。各フレームにはヘッダーがあり、そこに、そのフレームの長さとタイプ、ブール型フラグ、予約ビット、ストリーム識別子が格納されます (図 3 を参照)。

図 3. フレームの構成要素
フレームの構成要素を示す図
フレームの構成要素を示す図

長さ

Length フィールドには、フレームのサイズが記録されます。DATA フレームでは最大 224 バイト (約 16 MB) を伝送することができますが、デフォルでは最大値が 214 バイト (16 KB) に設定されます。フレーム・サイズは上流でネゴシエーション可能です。

タイプ

Type フィールドは、フレームの目的を識別します。目的は、以下の 10 タイプのうちのいずれかになります。

  • HEADERS: このフレームには HTTP ヘッダー情報だけが格納されます。
  • DATA: このフレームにはメッセージのペイロードのすべて、または一部が格納されます。
  • PRIORITY: ストリームに割り当てる重要度を指定します。
  • RST_STREAM: エラー (PUSH_PROMISE の拒否) を通知し、ストリームを終了します。
  • SETTINGS: 接続構成を指定します。
  • PUSH_PROMISE: クライアントにリソースをプッシュする意図を通知します。
  • PING: ハートビートおよびラウンドトリップ時間。
  • GOAWAY: 現在の接続に対するストリーム生成の停止を通知します。
  • WINDOW_UPDATE: ストリームのフロー制御を管理するために使用されます。
  • CONTINUATION: ヘッダー・フラグメントのシーケンスを続けるために使用されます。

各フレーム・タイプの詳細については、仕様のセクション 11.2 を参照してください。

フラグ

Flag フィールドは、フレームの状態に関する情報をブール値で示します。

  • DATA フレームでは、2 つのブール値フラグを定義できます。END_STREAM が設定されている場合、それはデータ・ストリームの終わりを意味します。PADDED は、パディングが使用されていることを意味します。
  • HEADERS フレームでは DATA フレームと同じフレームに加え、さらに 2 つのフラグを指定できます。END_HEADERS が設定されている場合、ヘッダー・フレームの終わりを意味します。PRIORITY は、ストリームの優先度が設定されていることを意味します。
  • PUSH_PROMISE フレームでは、END_HEADERS フラグおよび PADDED フラグを設定できます。

その他すべてのフレーム・タイプでは、フラグを設定することはできません。

ストリーム識別子

ストリーム識別子は、論理ストリームに属するフレームを追跡するために使用されます。フレームは、一度に 1 つのメッセージおよびストリームだけに属することができます。ストリームでは優先度を通知することができます。これにより、そのストリームに割り振るネットワーク・リソースを決定しやすくなります。ストリームの優先度については、このあと詳しく説明します。

リクエスト/レスポンスの多重化

TCP 接続が単一の場合に問題となるのは、一度に 1 つのリクエストしか実行できないことです。したがって、クライアントはレスポンスを受け取ってからでないと、別のリクエストを開始できません。これが、「ヘッド・オブ・ライン・ブロッキング」と呼ばれる問題です。前述のとおり、標準的な次善策は複数の接続 (リクエストごとに 1 つの接続) を開くことですが、メッセージを小さい独立した部分に分割し、接続を介してそれらの部分を送信できるとしたら、この問題は即座に解消されます。

これがまさに、HTTP/2 が達成しようとしている目標です。メッセージをフレームに分割し、それらのフレームにストリーム識別子を割り当てて単一の TCP 接続を介して独立して送信するという手法により、リクエストおよびレスポンス・メッセージの完全な双方向多重化が可能になります (図 4 を参照)。

図 4. インターリーブされて TCP 接続を介して送信されるフレーム
インターリーブされて TCP 接続を介して送信されるフレームを示す図
インターリーブされて TCP 接続を介して送信されるフレームを示す図

図 4 は、単一の接続を介して送信されている 3 つのストリームを示しています。具体的には、サーバーが 2 つのレスポンスを送信し、クライアントが 1 つのリクエストを送信しています。

サーバーはストリーム 1 内でレスポンスの HEADERS フレームを送信します。ストリーム 2 内では、別のレスポンスの HEADERS フレームの後に続けて、両方のレスポンスの DATA フレームを送信します。2 つのレスポンスは以下の図に示すようにインターリーブされます。サーバーがレスポンスを送信するのと並行して、クライアントはリクエストを開始するために、新しいメッセージの HEADERS フレームと DATA フレームを送信します。これらのフレームもレスポンス・フレームとインターリーブされます (以下の図を参照)。

図 5.HTTP/2 でのリクエスト/レスポンス・ストリームのインターリーブ
HTTP/2 でのリクエスト/レスポンス・ストリームのインターリーブを示す図
HTTP/2 でのリクエスト/レスポンス・ストリームのインターリーブを示す図

受信側では、すべてのフレームが 1 つに再アセンブルされて、完全なリクエストまたはレスポンス・メッセージという形になります。

フレームをインターリーブさせるメリットは、いくつもあります。

  • すべてのリクエストとレスポンスが単一のソケットを介して行われます。
  • レスポンスまたはリクエストが他のレスポンス/リクエストをブロックすることはありません。
  • 待ち時間が短縮されます。
  • ページにロードできるリソースの量が増えます。
  • HTTP 1.1 ハックの必要がなくなります。
図 6. HTTP リクエストと HTTP/2 フレームとのマッピング
HTTP リクエストと HTTP/2 フレームとのマッピングを示す図
HTTP リクエストと HTTP/2 フレームとのマッピングを示す図

図の左側に示されている HTTP リクエストは、右側の HEADERS フレームに対応しています。

HEADERS フレーム内には 2 つのフラグが設定されています。最初の END_STREAM フラグは (プラス記号で示されているように) true に設定されていて、このフレームがこの特定のリクエストの最後のフレームであることを示しています。END_HEADERS フラグも同じく true に設定されています。これは、このフレームがヘッダー情報を含むストリーム内で送信される最後のフレームであることを意味します。

HEADERS フレームに含まれるヘッダー・プロパティーは、HTTP 1.1 リクエスト内で設定されるヘッダー・プロパティーを反映します。これは、HTTP/2 は HTTP プロトコルのセマンティクスを維持しなければならないためです。

次は、このリクエストに対するレスポンスを見ていきましょう。

HTTP レスポンスと HTTP/2 フレームとのマッピング

図 7 の左側に示されているのは HTTP 1.1 ヘッダー・レスポンスです。右側には、このレスポンスと同じものを、2 つの HTTP/2 フレーム (HEADERSDATA) を使用して表現したレスポンスが示されています。

図 7. HTTP レスポンスと HTTP/2 フレームのマッピング
HTTP レスポンスと HTTP/2 フレームのマッピングを示す図
HTTP レスポンスと HTTP/2 フレームのマッピングを示す図

HEADERS フレームに含まれる END_STREAM は、このフレームがこのストリーム内で送信される最後のフレームではないことを示しています。一方、END_HEADER は、これがヘッダー情報を含む最後のフレームであることを示しています。DATA フレームに含まれる END_STREAM は、これが最後のフレームであることを示しています。

ヘッダー圧縮

HTTP/2 プロトコルには HPACK が伴います。HPACK の目的は、クライアント・リクエストとサーバー・レスポンス間でのヘッダー情報の重複によって生じるオーバーヘッドを削減することです。ヘッダー圧縮は、すでに送信されたヘッダー・フィールドのリストをクライアントとサーバーの両方に維持させることによって可能になります。このリストを使用して以降のメッセージを作成し、それらのメッセージでは送信済みのヘッダー・リストを参照させるという仕組みです。

図 8.同じ接続を介した 2 つのリクエストのヘッダー圧縮
同じ接続を介した 2 つのリクエストのヘッダー圧縮を示す図
同じ接続を介した 2 つのリクエストのヘッダー圧縮を示す図

図 8 に示されている 2 つのリクエストのヘッダー情報は重複しています。この 2 つのリクエストの違いは、黄色で強調表示されているリクエスト対象のリソースだけです。そこで活躍するのが、HPACK ヘッダー圧縮です。最初のリクエストを受信したサーバーがそのリクエストのヘッダー部分のリストを維持していれば、サーバーへの以降のリクエストでは、ヘッダー全体を送信するのではなく、以前のリクエストとの差分を送信するだけで済みます。ヘッダーの値が設定されていない限り、以降のリクエストのヘッダーには前のリクエストと同じ値が設定されていると見なされます。

ストリームの優先度

メッセージ・フレームはストリームを介して送信されます。各ストリームには優先度が割り当てられて、その優先度によって、そのストリームが処理される順番、さらにはストリームを処理するために割り当てられるリソースの量も決まってきます。

優先度はヘッダー・フレームに挿入されます。あるいは、特定のストリームの優先度フレームに挿入されることもあります。優先度の値は、0 ~ 256 の範囲で指定できます。

依存関係を定義すると、ある特定のリソースを他のリソースより先にロードすることができます。開発者が各ストリームに割り当てられる重みをより柔軟に制御できるよう、依存関係ツリーには優先度も加えられるようになっています。

図 9. ストリームの優先度を表す依存関係ツリー
ストリームの優先度を表す依存関係ツリーの図
ストリームの優先度を表す依存関係ツリーの図

図 9 では、文字がストリーム識別子を表し、数字が各ストリームに与えられる重みを表します。ツリーのルートにあるストリーム A には、従属ストリーム B および C よりも先にリソースが割り当てられます。ストリーム B には利用可能なリソースの 40 パーセントが割り当てられる一方、ストリーム C に割り当てられるのは利用可能なリソースの 60 パーセントです。ストリーム C を親として持つストリーム D とストリーム E には、ストリーム C から均等にリソースが割り当てられます。

ストリームの優先度は、サーバーに対する提案に過ぎません。優先度が臨機応変に変更されることや、完全に無視されることもあります。ワークグループは HTTP/2 プロトコルのドラフトを作成する際に、特定のリソース割り当てに従うようクライアントからサーバーに義務付けるのは誤っていると判断したのです。そのため、サーバーは自身の機能に合わせて自由に優先度を調整できるようになっています。

サーバー・プッシュ

サーバー・プッシュ機能により、サーバーはクライアント・リクエストに必要なリソースを予測できるようになります。サーバーはその予測に基づいて、リクエストの処理を完了する前にリソースをクライアントに送信するという仕組みです。

サーバー・プッシュのメリットを理解するために、画像と CSS ファイルや JavaScript などのその他の依存関係からなる Web ページを考えてみてください。その Web ページを、クライアントが単純にリクエストするとします。すると、サーバーはリクエストされた Web ページを分析し、ページをレンダリングするために必要なリソースを判断し、それらのリソースをクライアントのキャッシュに先行送信します。サーバーはこのすべての処理を、まだ元の Web ページのリクエストを処理している間に行います。したがって、クライアントが元の Web ページのリクエストに対するレスポンスを受信するまでには、必要なリソースがすでにキャッシュ内にあるというわけです。

HTTP/2 では、サーバー・プッシュによってクライアントに負担がかからないようになっています。サーバーは送信しようとするリソースごとに PUSH_PROMISE フレームを送信しますが、クライアントはレスポンスとして RST_STREAM フレームを返すことで、そのプッシュを拒否できるからです (例えば、該当するリソースがブラウザーのキャッシュ内にすでに存在する場合)。重要な点は、レスポンス・データを送信する前にすべての PUSH_PROMISE を送信して、クライアントがリクエストする必要のあるリソースを把握できるようにすることです。

フロー制御

フロー制御では、受信側が送信側からの大量のデータに圧倒されないよう、データ転送を管理します。フロー制御により、受信側がデータの送信を停止させたり、送信されるデータの量を減らしたりできます。一例として、オンデマンドで動画を配信するストリーミング・サービスを考えてください。閲覧者がストリーム配信される動画を観ている間、サーバーはクライアントにデータを送信し続けます。動画が一時停止されると、クライアントはキャッシュの枯渇を防ぐために、サーバーに対して動画データの送信を停止するよう通知します。

接続がオープンされると同時に、サーバーとクライアントは SETTINGS フレームを交換してフロー制御枠のサイズを設定します。デフォルトでは、サイズは約 65 KB に設定されますが、別のフロー制御枠のサイズを設定する WINDOW_UPDATE フレームを送信することで、デフォルトのサイズを制御できます。

HTTP/2 の普及状況

ベンダーによる HTTP/2 の採用はほぼ普遍的になっています。ブラウザー分野では、現在、主要なブラウザーのすべてが TLS に優先して新しいプロトコルをサポートしています。この記事を書いている時点で、グローバル・サポートは 80 パーセントを超えています。

サーバー・サポートはさらに進んでいて、主要なサーバー・ファミリーのすべてが HTTP/2 の最新バージョンをサポートしています。したがって、利用しているホスティング・プロバイダーがすでに HTTP/2 をサポートしている可能性は十分にあります。HTTP/2 の既知のあらゆるサーバー実装を、この仕様の Wiki ページで追跡できます。

ツール・サポートも広がっているため、お気に入りのユーティリティーはすべて HTTP/2 をサポートしているはずです。とりわけ、サーバーとクライアント間の HTTP/2 通信をデバッグしようとする開発者にとって最も重要なユーティリティーは Wireshark です。

HTTP/2 と開発者

Web ユーザーは、サイトの動作が高速である限り、コンテンツ配信に使用されているプロトコルには気を留めません。サイトでのリソースのロード方法を最適化することで、開発者はすでに顧客の要望を叶えるよう取り組んでいますが、HTTP/2 を使用すれば、ファイルを連結する必要も、アイコンを 1 つの画像ファイルにまとめる必要も、多数のドメインをセットアップする必要も、リソースをインライン化する必要もなくなります。

要するに、HTTP/2 によって次善策の必要がなくなるというわけです。実際のところ、この記事で説明したパフォーマンス・ハックを使い続けていると、HTTP/2 によるパフォーマンス強化のメリットをサイトで利用できなくなる可能性があります。

ほとんどの開発者にとって難しい質問となるのは、Web サイトを HTTP/2 用にリファクタリングするタイミングです。私としては、そのタイミングはアプリケーションの構成に関する要因、そして使用するブラウザーに大きく依存すると思います。古いブラウザーを使用しているユーザーに不利にならないようにすると同時に、ユーザー・エクスペリエンス全体の高速化を図るよう、バランスを取らなければなりません。

HTTP/2 を対象とした最適化は、ベスト・プラクティスに関してはなおさらのこと、未知の領域にあります。HTTP/2 に向けて最適化するということは、次善策を除去して最善の結果を期待するというだけのことではありません。開発者の 1 人ひとりが自ら調査する必要があります。調査を進める中で、最大限のパフォーマンスを引き出す新しい方法や、HTTP/2 が実際のインターネットでどのように機能するか、どのサーバーの実装が最もパフォーマンスに優れているかなどがわかってくるでしょう。

HTTP/2 は、新たに開かれた Web デプロイメントの世界を表します。この新しい世界が提示するチャレンジを受け入れる果敢な開発者は、HTTP/2 のメリットを享受することになるでしょう。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development
ArticleID=1056224
ArticleTitle=HTTP/2 の内幕
publish-date=01112018