HTTP/2 をなんとなく理解した気になれる話 / Understanding HTTP2

Ed264e55e2485e61c32aa8c8a93ffafe?s=47 veigr
February 14, 2020

HTTP/2 をなんとなく理解した気になれる話 / Understanding HTTP2

Ed264e55e2485e61c32aa8c8a93ffafe?s=128

veigr

February 14, 2020
Tweet

Transcript

  1. HTTP/2 を なんとなく理解した気になれる話

  2. 目標と対象 • 目標 • HTTP/2 をなんとなく理解した気になれる • 間違いがあったらごめんなさい • 対象

    • TCP/IP と HTTP/1.1 をなんとなく理解してる人
  3. 自己紹介 • ゔぇい • Twitter: @veigr • Web: https://www.cat-ears.net •

    ♥: C#, Kotlin, WPF, DDD, Clean Architecture … • 業務アプリケーション開発者 • 趣味で HTTP Proxy を作っている者 • とりあえず RFC 通り(多分)動くものを作って満足してしまった • HTTP/1.1, HTTP/2, WebSocket は完全に理解した(
  4. HTTP/2 概要

  5. HTTP/2 とは • 目的 • ネットワークリソースの効率的な利用とレイテンシ削減 • 方法 • 同一

    TCP Connection 上での通信の多重化 • ヘッダーフィールドの圧縮 • HTTP の意味論的な(セマンティクス)部分の変更はない • ので、アプリケーションレベルでは意識する機会は少ない • 実はもう結構使われてる • 標準規格 • RFC 7540 HTTP/2 • RFC 7541 HPACK (ヘッダーフィールド圧縮方式)
  6. HTTP/2 と HTTP/1.1 の差異 • HTTP/1.1 は 2020/02 現在 6

    つの RFC から構成されている • RFC 7230 Message Syntax and Routing • 構文と通信方法的な感じ • RFC 7231 Semantics and Content • HTTP の意味論と内容的な感じ • RFC 7232 Conditional Requests • 条件付きリクエスト • RFC 7233 Range Requests • 範囲リクエスト • RFC 7234 Caching • キャッシュ • RFC 7235 Authentication • 認証 通信の仕方 HTTP の中身 ほぼオプション
  7. HTTP/2 と HTTP/1.1 の差異 • HTTP/1.1 は 2020/02 現在 6

    つの RFC から構成されている • RFC 7230 Message Syntax and Routing • 構文と通信方法的な感じ • RFC 7231 Semantics and Content • HTTP の意味論と内容的な感じ • RFC 7232 Conditional Requests • 条件付きリクエスト • RFC 7233 Range Requests • 範囲リクエスト • RFC 7234 Caching • キャッシュ • RFC 7235 Authentication • 認証 通信の仕方 HTTP の中身 ほぼオプション HTTP/2 で変わるのは ここだけ! RFC 7230 → 7540
  8. Client Server HTTP/2 と HTTP/1.1 の差異 • メッセージの中身は変わらないが、通信方法だけ変わる Request Message

    Semantics Method : GET Path : / UA : Mozilla/5.0 (… … Response Message Semantics Status : 200 Date : 2020/01/01 00:00:00 Content-Type : text/html … 変わらない 変わる! Response Message Syntax HTTP/1.1 200 OK Date : 2020/01/01 00:00:00 Content-Type : text/html … Request Message Syntax GET / HTTP/1.1 User-Agent : Mozilla/5.0 (… …
  9. HTTP/2 の仕様一覧 (主観) • 通信の開始 • プロトコルアップグレード方法 など • 通信の制御

    • ストリームとその多重化 • フロー制御、優先度、依存関係 など • 通信の中身 • バイナリ通信のフォーマット • HTTP メッセージの表現形式の変更 • サーバープッシュ • CONNECT メソッドの変更 • ヘッダーフィールドの圧縮方法 (HPACK) など ここの一部だけ 話します
  10. HTTP/2 通信の開始

  11. HTTP/2 通信の開始 • https の場合 • TLS 拡張機能の ALPN (Application

    Layer Protocol Negotiation) • TLS ハンドシェイク(開始)時に内部プロトコルを交渉する機能 • ブラウザ実装は https しか対応してないケースが大半なので大体これ • SslStream でのサポートは Core 2.1, Standard 2.1 以降 • http の場合 • HTTP/1.1 で開始し、Upgrade ヘッダーによりプロトコルアップグレード • 事前同意の場合 • Alt-Svc ヘッダーなどで事前に HTTP/2 対応であることを知っておく • 平文でのみ利用可
  12. HTTP/2 通信の開始 – https の場合 TLS ClientHello 使えるプロトコルリスト (ALPN) ・HTTP/1.1

    ・HTTP/2 TLS ServerHello 選択したプロトコル (ALPN) ・HTTP/2 Client Server
  13. HTTP/2 通信の開始 – http の場合 Client Server GET / HTTP/1.1

    Host: Example.com Connection: upgrade Upgrade: h2c HTTP/1.1 101 Switching Protocols Connection: upgrade Upgrade: h2c
  14. HTTP/2 通信の制御

  15. TCP Connection Client Server TCP Connection HTTP/1.0 の Request /

    Response • 1 つの TCP Connection の中に 1 つの Request / Response • TCP Connection の消費が激しい HTTP Request 1 HTTP Response 1 HTTP Request 2 HTTP Response 2
  16. Client Server TCP Connection HTTP/1.1 の Request / Response •

    1 つの TCP Connection の中に複数の Request / Response • Request / Response の並列処理ができない HTTP Request 1 HTTP Response 1 HTTP Request 2 HTTP Response 2
  17. Client Server TCP Connection HTTP/2 の Request / Response •

    1 つの Request / Response を Stream という概念でラップ • 1 つの Request / Response の交換で 1 つの Stream を完全に消費 HTTP/2 Stream HTTP Request HTTP Response
  18. Client Server TCP Connection HTTP/2 の Request / Response •

    1 つの TCP Connection の中に複数の Stream • 複数の Stream (Request / Response) を並列処理 (多重化) できる HTTP/2 Stream HTTP/2 Stream HTTP/2 Stream
  19. HTTP/2 の Stream とは • HTTP/2 の Stream は、Stream ID

    で HTTP アプリケーション内の Request / Response ペアを識別するレイヤー • TCP/IP 通信は上位レイヤーになるにつれて通信相手をより詳細に 識別する • これにより Request / Response の並列処理 (多重化) が可能に レイヤー 方法 識別対象 IP IP アドレス 端末 TCP TCP ポート 端末内のアプリケーション HTTP/2 Stream Stream ID アプリケーション内の Request / Response ペア
  20. • HTTP/2 は Frame という単位でバイナリ通信を行う • Frame は Stream ID

    を持ち、所属 Stream を識別できる TCP Connection Client Server Stream は Frame によって構成される <Frame> Stream 7 HEADERS <Frame> Stream 5 HEADERS <Frame> Stream 3 DATA <Frame> Stream 1 DATA <Frame> Stream 3 DATA Stream 1 Buffer <Frame> Stream 1 HEADERS <Frame> Stream 1 DATA Stream 1 Buffer <Frame> Stream 1 HEADERS Stream 3 Buffer <Frame> Stream 3 HEADERS Stream 3 Buffer <Frame> Stream 3 HEADERS
  21. • HTTP/2 は HTTP/1.1 と違い管理すべき状態がいくつも存在する • 各 Stream バッファ、依存関係、優先度、HPACK の動的テーブル、

    Connection の設定 など TCP Connection Client Server HTTP/2 はステートフル <Frame> Stream 7 HEADERS <Frame> Stream 5 HEADERS <Frame> Stream 3 DATA <Frame> Stream 1 DATA <Frame> Stream 3 DATA Stream 1 Buffer <Frame> Stream 1 HEADERS <Frame> Stream 1 DATA Stream 1 Buffer <Frame> Stream 1 HEADERS Stream 3 Buffer <Frame> Stream 3 HEADERS Stream 3 Buffer <Frame> Stream 3 HEADERS ステート フル! ステート フル!
  22. Client Server TCP Connection 補足: Stream ID • クライアントから開始された Stream

    ID は奇数、サーバーからは偶数 • Stream ID 0 の Stream は Connection 制御用 • 設定を変更したり、切断したり、Ping を投げたりする • ID を使い切ったら切断して再接続する HTTP/2 Stream ID 0 HTTP/2 Stream ID 1 HTTP/2 Stream ID 3
  23. Frame と Message の変換

  24. Frame と Message の変換 • HTTP/2 Message は HTTP/2 Frame

    に変換されて送受信される HTTP/2 Message (Request or Response) HTTP/2 Frame HTTP/2 Frame HTTP/2 Frame HTTP/2 Frame
  25. Frame Format フィールド ビット数 説明 Length 24 フレームペイロードの長さ。24ビット符号なし整数。 Type 8

    フレームのタイプ。 Flags 8 各タイプ固有のフラグ。 R 1 予約済みビット。 Stream Identifier 31 Stream ID。31ビット符号なし整数。 Frame Payload 0… 各タイプ固有のペイロード。 +-----------------------------------------------+ | Length (24) | +---------------+---------------+---------------+ | Type (8) | Flags (8) | +-+-+-----------+---------------+-------------------------------+ |R| Stream Identifier (31) | +=+=============================================================+ | Frame Payload (0...) ... +---------------------------------------------------------------+ 出典: RFC 7540 4.1 ヘッダー
  26. Frame Types タイプ 概要 HEADERS HTTP メッセージヘッダーを転送する CONTINUATION ヘッダー内容の続きを転送する DATA

    HTTP メッセージボディーを転送する PUSH_PROMISE サーバープッシュ用ストリームの作成指示と共に、 予想リクエストヘッダーを転送する PRIORITY ストリーム優先度を変更する WINDOW_UPDATE フロー制御ウィンドウサイズを変更 SETTINGS 通信設定を共有する PING Ping RST_STREAM ストリームを切断する GOAWAY コネクションの終了や重大なエラー通知
  27. HTTP/2 Message Frame → Message 変換 - Body が空の場合 HEADERS

    Frame -- Flags -- END_HEADERS=False END_STREAM=True Header Block Fragment CONTINUATION Frame -- Flags -- END_HEADERS=True Header Block Fragment HPACK Headers … Connection 両端でヘッダーフィールドキャッシュし 再送を抑制する感じの仕組み Body (空)
  28. HTTP/2 Message Frame → Message 変換 - Body がある場合 DATA

    -- Flags -- END_STREAM=False Data DATA -- Flags -- END_STREAM=True Data Headers Body … … HEADERS -- Flags -- END_HEADERS=False END_STREAM=False Header Block Fragment CONTINUATION -- Flags -- END_HEADERS=True Header Block Fragment HPACK …
  29. Message の HTTP/1.1 からの変更点 • メッセージの表現(Syntax)は変わっているが、 意味(Semantics)的にはほぼ一緒 • Request Line

    / Status Line にあったような内容 は擬似ヘッダーフィールド(:methodとか)に変更 • reason-phrase (OK とか Not Found とか)は廃止 • ヘッダーフィールド名は小文字に統一 • Host が廃止され :authority に • :scheme 擬似ヘッダーフィールドが追加され、 メッセージからプロトコルスキームが判別可能に HTTP/2 Message Syntax 例 -- Headers – :authority: www.cat-ears.net :method: POST :path: / :scheme: https accept-language: ja user-agent: Mozilla/5.0 (… … -- Body – …
  30. サーバープッシュ

  31. /index.html サーバープッシュの目的 • クライアントがリクエストしたページに紐付くリソース(js/css)を、 サーバーがページよりも先行して送信することで通信を効率化する • HTTP/2 ではサーバー側から Stream を開始できる

    Client Server GET /index.html /hoge.css /hoge.js /index.html hoge.css hoge.js
  32. サーバープッシュの実現方法 Client Server PUSH_PROMISE Frame 予約 Request Headers -- :method:

    GET :path: /hoge.css … /hoge.css Request Headers (Push Promise) /hoge.css をキャッシュ /index.html Response /hoge.css Response GET /index.html /index.html 内で必要な /hoge.css をキャッシュで解決 /index.html には /hoge.css が必要
  33. サーバープッシュの実現方法 Client Server PUSH_PROMISE Frame 予約 Request Headers -- :method:

    GET :path: /hoge.css … /hoge.css Request Headers (Push Promise) /hoge.css をキャッシュ /index.html Response /hoge.css Response GET /index.html /index.html 内で必要な /hoge.css をキャッシュで解決 /index.html には /hoge.css が必要 • 安全かつキャッシュ可能 でなければならない (GET or HEAD) • Body は持てない キャッシュ汚染防止の為 権限のないリソースは サーバープッシュ不可
  34. おまけ: .NET での HTTP/2

  35. HttpClient の HTTP/2 対応 • .NET Framework • HttpClientHandler では利用不可

    • WinHttpHandler (要NuGet & fw4.6 & Win10 1607)を利用すれば利用可 • .NET Core • ~2.0 : Win10 1607~のみ利用可? • WinHttpHandler を使ってる (元々 Core 用に作られたものっぽい) • 2.1~2.2 : 利用不可 • SocketsHttpHandler に移行したため • ただし WinHttpHandler を利用するよう構成すれば Windows では利用可 • 3.0~ : 利用可 • SocketsHttpHandler の HTTP/2 対応?
  36. HttpClient の HTTP/2 利用方法 (Core 3.x) var client = new

    HttpClient(); using var request = new HttpRequestMessage(HttpMethod.Get, "https://www.cat-ears.net/") { Version = new Version(2, 0) }; using var response = await client.SendAsync(request); Console.WriteLine(response.Version); var client = new HttpClient() { DefaultRequestVersion = new Version(2, 0) }; using var response = await client.GetAsync("https://www.cat-ears.net/"); Console.WriteLine(response.Version); OR
  37. サーバーサイドでの HTTP/2 • クライアントと違って通信スタックは原則アプリ外 • ので Kestrel や HTTP.sys、IIS 等ホスティング環境などに依存

    • サーバープッシュ API の追加は .NET Framework 4.6 以降 • ASP.NET Core には実装されてなさそう
  38. まとめ • HTTP/2 は HTTP/1.1 から通信の仕方が変わっているだけで、 HTTP メッセージの意味的には変わっていない • 通信の効率化だけが目的

    • HTTP/2 はステートフルなバイナリ通信 • 1 つの TCP Connection 上に Stream という通信レイヤーを用意 • Stream の中で Frame を用いてメッセージのやり取りと通信制御を行う