HTTP2 最速実装 〜入門編〜

25,303 views

Published on

HTTP 2 最速実装(最小限の機能で素早く実装)するために必要最小限の知識を伝えます。
HTTP 2 最速実装法: https://github.com/http2jp/http2jp.github.io/wiki/HTTP2.0-%E6%9C%80%E9%80%9F%E5%AE%9F%E8%A3%85%E6%B3%95

h2-12 (draft-ietf-httpbis-http2-12) 対応の修正をしました。
http://tools.ietf.org/html/draft-ietf-httpbis-http2-12

Published in: Technology
3 Comments
72 Likes
Statistics
Notes
No Downloads
Views
Total views
25,303
On SlideShare
0
From Embeds
0
Number of Embeds
3,806
Actions
Shares
0
Downloads
115
Comments
3
Likes
72
Embeds 0
No embeds

No notes for slide

HTTP2 最速実装 〜入門編〜

  1. 1. HTTP2最速実装 ~入門編~ 前田 薫 (@mad_p) http2 ハッカソン #1 2014/02/23 ドラフト12に合わせ修正 2014/05/12 1
  2. 2. はじめに • 今日の目標 • HTTP2の処理系を最小限の労力で作れるようになる(性能は求めない) • HTTP2.0 最速実装法が実装できるようになる • https://github.com/http2jp/http2jp.github.io/wiki/HTTP2.0- %E6%9C%80%E9%80%9F%E5%AE%9F%E8%A3%85%E6%B3%95 • HTTP2, HPACKの概要を理解する • http://tools.ietf.org/html/draft-ietf-httpbis-http2-12 (このスライドはドラフト12ベースです) • http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07 2
  3. 3. 目次 • HTTP2 Overview • HTTP2の開始 • Frame定義 • HTTPメッセージの交換 • Stream管理 • HPACK(ヘッダ圧縮) • まとめ 3
  4. 4. おさらい: HTTP 1.1 client server ①Request ②Response 4 connection
  5. 5. HTTP 1.1 REQUEST/RESPONSE • テキスト形式、行指行 5 GET / HTTP/1.1 User-Agent: curl/7.30.0 Host: localhost Accept: */* HTTP/1.1 200 OK Content-Length: 44 Content-Type: text/html <html><body><h1>It works!</h1></body></html> CR+LF Header Status Request Header Body CR+LF
  6. 6. HTTP2 OVERVIEW 6
  7. 7. HTTP2 OVERVIEW 7 client server connection ①Request ②Response stream ③Server-Push
  8. 8. CONNECTIONとSTREAM • Connectionの中にstreamがある • Streamは双方向 • Streamは複数同時に存在してもよい • Streamはinterleaveして送信される • Streamには番号がついている • Clientからスタートしたら奇数、 • Serverからだと偶数 • Stream 0番を全体の制御に使う • Request, Responseはstreamの中を通る 8 Stream 1 Stream 2 Stream 3
  9. 9. STREAMとFRAME • StreamはFrameという単位で送信される 9 client server
  10. 10. FRAME • バイナリ形式 • 1オクテット = 8ビット • 左から右、上から下の順で送出 10 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | R | Length (14) | Type (8) | Flags (8) | +-+-+-----------+---------------+-------------------------------+ |R| Stream Identifier (31) | +-+-------------------------------------------------------------+ | Frame Payload (0...) ... +---------------------------------------------------------------+
  11. 11. HTTPメッセージのFRAME表現 • HTTP 1.1 Request • Request行 • Header部 • Body部(POST, PUTなど) • HTTP 2 • HEADERS frame(s) • Request行、Status行とヘッダ部を含む • DATA frames 11 HTTP/1.1 200 OK Content-Length: 44 Content-Type: text/html <html><body><h1>It works!</h1></body></html> :status: 200 content-length: 44 content-type: text/html <html><body><h1>It works!</h1></body></html> HEADERS DATA
  12. 12. HTTP2の開始 12
  13. 13. HTTP2の開始 • HTTP2でフレームを送りあって通信するまでに、接続を確立する手順 • HTTP 1.1 • 1. TCP接続を確立 • 2. (httpsスキームの場合) TLSの確立 • 3. リスエスト送信 • 4. レスポンス受信 • HTTP 2 • 1. Connectionの確立(最初のフレームの送出) → 詳細は次ページ • 2. その後のフレーム送受信 13
  14. 14. CONNECTION確立の方法 • TLS ALPN (Application Layer Protocol Negotiation extension) • TLSの拡張 • http://d.hatena.ne.jp/ASnoKaze/20130207/1360249692 • http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-05 • クライアントがClientHelloで使いたいプロトコルのリストを送る • サーバーがその中から使うものを決めてServerHelloで知らせる • TLS NPN (Next Protocol Negotiation extention) ALPNまでのつなぎ • https://technotes.googlecode.com/git/nextprotoneg.html • HTTP 1.1からのUpgrade • HTTP 1.1形式のリクエスト内に「Upgradeヘッダ」を書く、SETTINGSをヘッダとして送る • 事前知識によってTCP接続後にいきなりHTTP2 ← 最速実装ではこれを使います 14
  15. 15. HTTP2 CONNECTION PREFACE • クライアント → サーバー • 24オクテットのナゾの文字列を送る (HTTP 1.1からのUpgrade時も) • 505249202a20485454502f322e300d0a0d0a534d0d0a0d0a • アスキーの内容は「PRI * HTTP/2.0rnrnSMrnrn」 (PRISMが入ってるのは洒落) • その後ろにSETTINGSフレーム(後述)を送る • サーバー → クライアント • SETTINGSフレームを送る • SETTINGSフレーム: フロー制御、ヘッダ圧縮、同時接続ストリーム数などパラメータ を通知 15
  16. 16. FRAME定義 16
  17. 17. フレームについて • HTTPストリームの内容をフレームに分解して送る • ひとつのフレームで送れるペイロードは16383オクテットまで • バイナリ形式 17 00 40 01 05 00 00 00 01 00 07 3a 6d 65 74 68 6f 64 03 47 45 54 00 07 3a 73 63 68 65 6d 65 04 68 74 74 70 00 0a 3a 61 75 74 68 6f 72 69 74 79 0f 31 30 36 2e 31 38 36 2e 31 31 32 2e 31 31 36 00 05 3a 70 61 74 68 01 2f
  18. 18. FRAME FORMAT • フレームヘッダ 8オクテット • Length: ペイロードのオクテット数 • Type HEADERS, DATAなどフレームの種類を表わす整数 • Flags: タイプごとに定められた付加情報を持つ。特にEND_STREAM,END_HEADERSフラグが重要 • Stream Identifier: 31bitのストリームID • フレームペイロード: タイプごとに定められたデータ内容 18 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | R | Length (14) | Type (8) | Flags (8) | +-+-+-----------+---------------+-------------------------------+ |R| Stream Identifier (31) | +-+-------------------------------------------------------------+ | Frame Payload (0...) ... +---------------------------------------------------------------+
  19. 19. FRAME TYPES Type 意味 Type番号(draft 12) DATA データ 0x0 HEADERS ヘッダ 0x1 PRIORITY ストリームの優先度 0x2 RST_STREAM ストリームの異常終了 0x3 SETTINGS コネクションのパラメータ 0x4 PUSH_PROMISE サーバープッシュ 0x5 PING 死活監視+遅延測定 0x6 GOAWAY コネクション終了 0x7 WINDOW_UPDATE フロー制御パラメータ 0x8 CONTINUATION HEADERS, PUSH_PROMISEの続き 0x9 ALTSVC プロトコル切り換えの可能性を示す 0xa BLOCKED フロー制御デバッグ情報(draft-12のみ) 0xb 19
  20. 20. DATA FRAME(TYPE 0X0) • Data: • データ自体を運ぶ。HTTP Bodyに相当 • 長さはペイロードの残り全部 • Pad High, Pad Low: パディングの長さ • Padding: パディング • DATAフレームのフラグ: フレームヘッダの中のFlagsフィールドに置く • END_STREAM(0x1): ストリームの終了を示す • END_SEGMENT(0x2): 中継時に合体させてはいけない範囲を示す • PAD_LOW(0x8), PAD_HIGH(0x10): パディング長フィールドを使うかどうか示す • COMPRESSED(0x20): Dataがフレーム単位でgzip圧縮されているかを示す 20 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Pad High? (8) | Pad Low? (8) | +---------------+---------------+-------------------------------+ | Data (*) ... +---------------------------------------------------------------+ | Padding (*) ... +---------------------------------------------------------------+
  21. 21. HEADERS FRAME(TYPE 0X1) • Header Block Segment • Key-valueペアの列を運ぶ • HTTP Headerに相当 • HPACK形式で圧縮したもの • E, Stream Dependency, Weight: • ストリームの優先度情報 • Pad High, Pad Low, Padding: DATAフレームと同様 • HEADERフレームのフラグ • END_STREAM(0x1),END_SEGMENT(0x2), PAD_LOW(0x8), PAD_HIGH(0x10): DATAと同じ • END_HEADERS(0x4): ヘッダブロックがこのフレームで完結することを示す • PRIORITY(0x20): 優先度情報フィールド3つを使うかどうかを示す 21 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Pad High? (8) | Pad Low? (8) | +-+-------------+---------------+-------------------------------+ |E| Stream Dependency? (31) | +-+-------------+-----------------------------------------------+ | Weight? (8) | +-+-------------+-----------------------------------------------+ | Header Block Fragment (*) ... +---------------------------------------------------------------+ | Padding (*) ... +---------------------------------------------------------------+
  22. 22. SETTINGS FRAME(TYPE 0X4) • 5オクテットを1組として、ペイロード長 ぶんの設定が入っている • 接続確立時におたがいに送り合う • 接続中に送ってもよい • SETTINGSフレームのストリームIDは必ず0 • SETTINGSフレームのフラグ • ACK(0x1): 相手から送信されたSETTINGに対するACKを示す。このときペイロードは空 • SETTINGSを受け取ったら必すACKを返す(接続時の最初も) • Identifier: 設定の種類を表わす識別子 Value: 設定値 22 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identifier (8)| +---------------+-----------------------------------------------+ | Value (32) | +---------------------------------------------------------------+
  23. 23. SETTINGで定義されている設定 • 以下の設定のすべてを実装しないといけない(最速実装では無視します) • SETTINGS_HEADER_TABLE_SIZE (1): ヘッダ圧縮に使うテーブルサイズ(初期値:4096) • SETTINGS_ENABLE_PUSH (2): • サーバーからのpushを許すかどうか(初期値1: 許可)。クライアント側からの指定のみ意味がある • SETTINGS_MAX_CONCURRENT_STREAMS (3): • 同時にactive状態になってよいストリーム数。100以上を推奨(初期値:制限なし) • SETTINGS_INITIAL_WINDOW_SIZE (4): • 受信バッファサイズの初期値。フロー制御で使う。2^31 – 1 まで(初期値:65535) • SETTINGS_COMPRESS_DATA (5): • DATAフレームのgzip圧縮を使ってよいかどうか(初期値0:禁止) 23
  24. 24. GOAWAY FRAME(0X7) • これ以上ストリームを作るの禁止 • コネクションの終了を意図している (でも送出側は作ってもいいことになっている) • GOAWAYフレームのストリームIDは必ず0 • Last-Stream-ID: 処理中の最終ストリームID • 相手が直前に送ったものがアプリ層に届いたかわかる • Error Code: エラー情報 24 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |R| Last-Stream-ID (31) | +-+-------------------------------------------------------------+ | Error Code (32) | +---------------------------------------------------------------+ | Additional Debug Data (*) | +---------------------------------------------------------------+
  25. 25. これ以外のFRAME TYPES • 以下のフレームタイプは最速実装では使いません • PRIORITY • RST_STREAM • PUSH_PROMISE • PING • WINDOW_UPDATE • CONTINUATION • ALTSVC • BLOCKED 25
  26. 26. HTTPメッセージの交換 26
  27. 27. HTTPリクエスト/レスポンスの表現 • リクエスト行、レスポンス行、ヘッダ部の情報をHEADERSフレームで 表現 • フレーム長制限を超える場合はCONTINUATIONを使う(最速実装では使いません) • おさまり切る場合はEND_HEADERSフラグをつける • ボディ部をDATAフレームで表現 • ボディ部が存在しない場合はDATAフレームを生成せず、HEADERSに END_STREAMフラグをつける • DATAフレームは複数になってもよい。最後のものにはEND_STREAMフラグをつ ける • HEADERS, DATAフレームを順に送出 27
  28. 28. HEADERSの作り方 • リクエストには以下のヘッダ名を使う。リクエスト行の要素はコロンつ きのヘッダ名を使う • :method HTTPメソッド。GET, POSTなど • :scheme httpまたはhttpsのどちらか • :authority リクエストURIのauthority部分 www.example.com:8080など • :path パス • レスポンスではステータスを:status に入れる • この後HPACKで圧縮し、Frame headerと連結する 28
  29. 29. STREAM管理 29
  30. 30. STREAM IDの割当 • いままでに使った番号より大きな番号を使わないといけない • クライアント発の場合には奇数を使う • サーバー発の場合には偶数を使う(最速実装では使いません) • ストリームID 0(ゼロ)はコネクション全体の制御を使うために予約 • SETTINGSのMAX_CONCURRENT_STREAMSより多くのストリームを 同時に作ってはいけない • Open, half-closeのものを数える • 番号を使いつくしたら? → 新しいコネクションを作る 30
  31. 31. STREAM STATE DIAGRAM • ストリームのライフタイム定義 • Idle: 未作成 • Open: 使用中 • Half closed: • 片側だけ使用中の状態 • 片方からEND_STREAMを送った場合 • Closed: 終了 • Reservedは最速実装では使いませ ん 31 +--------+ PP | | PP ,--------| idle |--------. / | | v +--------+ v +----------+ | +----------+ | | | H | | ,---| reserved | | | reserved |---. | | (local) | v | (remote) | | | +----------+ +--------+ +----------+ | | | ES | | ES | | | | H ,-------| open |-------. | H | | | / | | | | | v v +--------+ v v | | +----------+ | +----------+ | | | half | | | half | | | | closed | | R | closed | | | | (remote) | | | (local) | | | +----------+ | +----------+ | | | v | | | | ES / R +--------+ ES / R | | | `----------->| |<-----------' | | R | closed | R | `-------------------->| |<--------------------' +--------+
  32. 32. HPACK(ヘッダ圧縮) 32
  33. 33. HPACKの必要性 • なにしろでかいんですよ、HTTPヘッダーって。同じ情報を何度も送るし • SPDYではzlibで圧縮していましたが、CRIME/BREACHアタックが出現 • 圧縮率観測攻撃: • データをつっこんでやって、圧縮されるかどうか見ると、同じペイロード内の情報 (セッションクッキーなど)を調べることができてしまう • 今日この後で勉強しましょう • HPACK: 圧縮率観測攻撃に耐える圧縮形式として設計 33
  34. 34. HPACKの圧縮手段 • Huffman Encoding • よく使う文字を少ないビット数で表現する • Static Table Indexing • よく使うヘッダをあらかじめ定義しておき、番号で指定する • Header Table Indexing • 最近送信したヘッダと同一だったら番号で指定する • Reference Set Difference • 最後に送出したヘッダとの差分だけを送る 34
  35. 35. HPACK最速実装 • 必ずリテラルで、Huffmanなしで、Without Indexモードで送る • 各ヘッダを以下の形式でエンコード • H: 0にする • Lengthは • 126 (2^7 – 2)以下はそのまま入れる • 127以上は最初に127 • 127を引いた残りを128進数で、 最後のもの以外はMSBを立てる 35 0 1 2 3 4 5 6 7 +---+---+---+---+---+---+---+---+ | 0 | 0 | 0 | 0 | 0 | +---+---+-----------------------+ | H | Name Length (7+) | +---+---------------------------+ | Name String (Length octets) | +---+---------------------------+ | H | Value Length (7+) | +---+---------------------------+ | Value String (Length octets) | +-------------------------------+
  36. 36. ヘッダの最速実装の例 36 :method: GET :scheme: http :path: / :authority: www.example.com 00 07 3a 6d 65 74 68 6f 44 03 47 45 54 00 07 3a 73 63 68 65 6d 65 04 68 74 74 70 : 00 に続いて長さ7 そしてヘッダ名 :method 長さ3 そしてヘッダ値 GET 00 :scheme httpこれをくり返し、全体の長さを数え て、 先頭にフレームヘッダをつける 長さ64オクテット(0x40)、stream_id = 1,、END_STREAM、END_HEADERS の場合 00 40 01 05 00 00 00 01
  37. 37. 最速実装のリクエスト・レスポンス 37
  38. 38. 38 client server CONNECTION PREFACE SETTINGS SETTINGS HEADERS HEADERS DATA GOAWAY :method GET : Stream ID = 1 END_HEADERS, END_STREAM Stream ID = 1 END_HEADERS, Stream ID = 1 END_STREAM SETTINGS ACK SETTINGS ACK serverからEND_STREAMが 来たらGOAWAYを送り、 TCP接続を切断
  39. 39. 39 client server 50 52 49 20 2a 20 48 54 54 50 2f 32 2e 30 0d 0a 0d 0a 53 4d 0d 0a 0d 0a 00 40 01 05 00 00 00 01 00 07 3a 6d 65 74 68 6f 64 03 47 45 54 00 07 3a 73 63 68 65 6d 65 04 68 74 74 70 00 0a 3a 61 75 74 68 6f 72 69 74 79 0f 31 30 36 2e 31 38 36 2e 31 31 32 2e 31 31 36 00 05 3a 70 61 74 68 01 2f CONNECTION PREFACE 00 00 04 00 00 00 00 00SETTINGS HEADERS 00 0f 04 00 00 00 00 00 03 00 00 00 64 04 00 00 ff ff 02 00 00 00 00 SETTINGS 以下略 00 00 04 01 00 00 00 00SETTINGS ACK 00 00 04 01 00 00 00 00SETTINGS ACK
  40. 40. まとめ 40
  41. 41. HTTP2最速実装に向けて • HTTP2の概要 • コネクション、ストリーム、フレーム • HTTP Request / Responseの表現形式 • HEADERSフレーム、DATAフレーム • HTTP2の開始シーケンス • HPACKで楽をする実装方法 41
  42. 42. 今日やらなかったこと • その他の開始ハンドシェイク • TLSからのALPN, HTTPからのUpgrade • フロー制御、優先度制御 • エラー処理 42

×