This page looks best with JavaScript enabled

Http2_stream

 ·  ☕ 4 min read

connection 特性

  1. 當發送一個 http2 請求的時候會建立一個 connection (TCP connection)
  2. 發送第二個請求的時候會延續使用第一個請求所建立的Connection
  3. 若是有多個 stream 的情況,每個 stream 是可以在同一個 tcp connection 併發傳輸,稱做為多路復用(multiplexing)

stream 特性

  1. 一條 TCP 連線上可以有多個處於 Open 狀態的 stream(併發傳輸)
  2. Client 可以主動建立 stream (ID基數 1,3,5,7,9…)
  3. Server 可以主動建立 stream (ID偶數 2,4,6,8,10…)
  4. 任何一端都可以自主關閉 stream
  5. 同一條 stream 裡面的 frame 都是有序地排列

Client 向 Server 請求時 Stream ID 會為基數(1,3,5,7,9…)

Server 向 Client 主動推送 Stream ID 會為偶數(2,4,6,8,10…)

frame 特性

  1. 可以包含一到多個 Header (Header很小只要一個message ,到Header很大會被切成多個frame)
  2. 可以包含零到多個 Data!

想像一下 http1.1 時的 body 跟 header 都變成了 frame
簡單的來說 body 也叫 frame , header 也叫 frame 只是裡面資料不同而已。

到這裡你能比較 http1.1 與 http2 的不同嗎 ?

  • 在 http1.1 中 每一次請求都要重新建立一個 tcp connection
  • 在 http1.1 中 每一次傳輸都要帶上重複的 header
  • 在 http1.1 中 資料都是以純文本的方式傳輸
  • 在 http1.1 中 server 無法主動推送資料給 client
  • 在 http1.1 中 header 沒有進行壓縮

本篇文章還會再深入一點點解析 http2 stream 的相關知識

stream status

可以觀察下圖 stream status 的狀態變化,所有的 stream 一開始會處於 idle 狀態,最終會結束於 closed 狀態。

了解各個狀態監視如何切換的,需要知道 接收/發送 了什麼 flag,下方我列出了幾種會發送或是接收的 flag。

  • HEADERS (H)
  • PUSH_PROMISE (PP)
  • END_STREAM (ES)
  • RST_STREAM (RST)

這邊會簡單的說明一下幾種可能的狀況

  • idle 狀態轉換

    • 當 stream 狀態處於 idle , server 收到 head (h) flag 時後會把當前 stream 進行狀態的切換,從圖中可以我們從看到 idle 收 h flag 後切換成 open 狀態。
    • 當 stream 狀態處於 idle 狀態,如果這時候 Server 想要推送消息給 Client 端,那Server 會發出 PUSH_PROMISE (PP) Flag 這時 Server 會處於 reserved 狀態,這時候就要準備發送後面的資料(Head+Data)。
  • Open 狀態轉換

    • 當 stream 狀態處於 open 狀態,這時我們如果發送(send)或是接收(recv) END_STREAM (ES) flag 的話,都會進入一個所謂的半關閉狀態(half closed)這時stream會等待接受flag進而轉變成close狀態。
  • reserved 狀態轉換

    • 當 stream 狀態處於 reserved 狀態,這時候Server 一但推送了第一筆資料的Head出去就會把狀態切換成半關閉狀態 (half closed) 等待接受flag進而轉變成close狀態。
  • half closed 狀態轉換

    • 當 stream 狀態處於 half closed 狀態,這時我們如果發送(send)或是接收(recv) END_STREAM (ES) 、RST_STREAM (RST) flag 的話,會把該 Stream 的狀態切換成Closed。

Data source:http2-in-action/

stream 的priorty順序

由於 http2 大量的運用在前後與端溝通上,就算工程師只關心後端服務之間的溝通也需要知道,關於 http2 stream 的 priorty 的相關知識可以幫助我們在設計服務的時候善用已經存在的欄位。

 +---------------+
 |Pad Length? (8)|
 +-+-------------+-----------------------------------------------+
 |E|                 Stream Dependency? (31)                     |
 +-+-------------+-----------------------------------------------+
 |  Weight? (8)  |
 +-+-------------+-----------------------------------------------+
 |                   Header Block Fragment (*)                 ...
 +---------------------------------------------------------------+
 |                           Padding (*)                       ...
 +---------------------------------------------------------------+

從上圖我們可以看到 E 、 Stream Dependency? 、 Weight? 三個欄位,這三個欄位就表示了 http2 stream 的 priorty 的狀態。

?表示是可以選的欄位

  • Stream Dependency : 表示依賴其他 Stream 當其他 Stream 完成才能換該 Stream
  • Weight : 表示該 Stream 的權重,預設值為 16 ,那可以設定的範圍在 1~256。

wireshark 動手做看看

直接從 wireshark 抓取 http2 的封包來觀察 priorty,看看 http2 priorty , Stream ID , Frame 到底是怎麼一回事。

下圖為 wireshark 抓取瀏覽器存取 https://www.nba.com/?37 的封包

Magic SETTINGS WINDOW_UPDATE

可以看到第一個封包是 client (192.168.51.150) 送往 server (23.11.187.239) 封包的簡易描述是 Magic 類型的封包,同時包含了SETTINGS frame 與 WINDOW_UPDATE。

Magic

  • 點開magic stream 的話可以看到 client 發送了一個 PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n

SETTINGS

  • 點開SETTINGS stream 的話可以看到 client 發送了好幾個設定值,告訴了Server 我要設定成這樣。
    • Header table size
    • Max concurrent streams
    • Max hader list size
    • Unknown

WINDOW_UPDATE

  • 點開WINDOW_UPDATE stream 的話可以看到 client 發送了一個設定,告訴Server最大我的資料只能傳輸多少。

Headers

可以看到 client 發送了好幾個 HEADS 給SERVER並且Stream ID 都是奇數,這表示Client 發送給Server 的請求Stream ID都會是奇數。接下來 Cleint 又分別要了 Head[3] , Head[5] , Head[7] 那這些 Header有什麼關聯?

stream ID priority

點開 Head[3] 可以看到這個請求的權重,那跟 Head[5] 有什麼差別

點開 Head[5] 可以看到 ,觀察後可以看到 Head[3] 的priority 大於 Head[5],權重計算後 Head[3] 要比 Head[5] 的資料更快被接收。

stream ID dependency

除了 priority 之外還有 stream ID dependency 可以從上圖觀察到這兩個請求都要依賴 stream ID 0,表示都要先接收完成stream ID 0才可以接收各自的資料。

Data

可以看到 Server 回傳了資料給 Client 端,如圖所示 Client 要了 Head[1]的資料, Server 就回傳了六筆資料給 Client 。

小結

重新複習了 http2 的特性,以前常提到得多路復用(multiplexing),Stream 以及 Frame 到底是什麼又有什麼特性,以及當 Client/Server 發送或是接收請求後 connection 會處於什麼狀態 做一個簡單的分析與介紹。
最後從 wireshark 觀察 http2 請求的內容,觀察 Stream ID 與 Stream ID priority ,共用同一個 Connection 有些請求需要先被執行才能在執行其他請求的依賴關係,除此之外 沒有依賴關係的請求需要按照 priority 的大小 優先處理。


Meng Ze Li
WRITTEN BY
Meng Ze Li
Kubernetes / DevOps / Backend

What's on this Page