Http/2
"Connection management is a key topic in HTTP". This is how MDN begins its story of raising HTTP/2. Starting from the naive short-lived connections through keep-alive connections and the HTTP/1.1 pipeline, the story ends with a new protocol - HTTP/2 and the newest HTTP/3. All this is around the HOL blocking problem, the same issue as in a regular FIFO queue - some element in the queue (in our case this element is a request) may require a long time to be processed, and all consequences elements are standing in wait.
The last HTTP/1.1 attempt to fight the connection management was pipelining. The technique uses the same TCP connection to send multiple HTTP requests without waiting for the corresponding responses. But even the HTTP/1.1 pipeline is subject to the HOL problem because the responses were sent back in order.
HTTP/1.1 pipeline processing is initiated by setting the "Keep-Alive" HTTP header in addition to "Connection" (that alone usually initiates a Persistent connection).
GET /index.html HTTP/1.1
Connection: Upgrade, Keep-Alive
Keep-Alive: timeout=5, max=100
Content-Type: text/html; charset=UTF-8
To move step forward from here we need to realize that that main performance bottleneck in the picture above is the order - the responses need to be read in the same order as they written to the connection. Hence, the HOL issue.
The order may be combated by the streaming: let's imagine that each request/response expoits its own stream of data. Firstly for request's data and then when the response it ready (even partly) for the output data.
Define the frame (stream) as following:
+-----------------------------------------------+
| Length (24) |
+---------------+---------------+---------------+
| Type (8) | Flags (8) |
+-+-------------+---------------+-------------------------------+
|R| Stream Identifier (31) |
+=+=============================================================+
| Frame Payload (0...) ...
+---------------------------------------------------------------+
Possible values for Type - DATA(0), HEADERS(1), RST_STREAM(3), SETTINGS(4), WINDOW_UPDATE(8)
For example, consider the following WireShart dissertion:
The selected packet is marked as GRPC protocol (after context menu "Decode as...")
And now let's look at "Packet Details" and "Packet Bytes" panes. We can observer four HTTP/2 segments (frames) here: MAGIC, SETTINGS, HEADERS and DATA.
MAGIC is a special case - it is only contains the special sequence ("PRI * HTTP/2 ...") and used for initiate the HTTP/2 conversation
SETTINGS (Type=4) frame is obey the mentined structure, but its length is 0 rather as flags and stream identifier
HEADERS (Type=1) frame is fully obeyed frame. In our example it has the flags = End Stream) and the identifier (=1) followed by pseudo-headers (started with semicolns, : - :authority, :method, :path: /oauth2/OtpProcessor/StreamTime and :scheme) and natural headers (grpc-accept-encoding, content-type: application/grpc etc.)
DATA (Type=0) - full frame containing stream (=1) and small (5 bytes) data payload