로고

network / Oct 16, 2025

Why Did HTTP/1.1 Pipelining Disappear?

network• ·

HTTP/1.1 pipelining is a feature that reduces RTT waste by sending multiple requests consecutively over the same connection without waiting for the previous response. However, since the server had to send responses in the order they were received, this led to application-layer Head-of-Line (HOL) blocking, where a delay in the first response would block subsequent, faster responses. Due to this limitation and the difficulty of error recovery, it was not widely adopted, and HTTP/2’s stream multiplexing took its place.

HTTP/1.0: By Default, a New Connection for Each Request

The default model in HTTP/1.0 is non-persistent connections. For each resource request—such as HTML, CSS, or images—a TCP connection is established, the response is received, and the connection is closed.

Flowchart of non-persistent connections, where a new TCP connection is created for each HTTP request

Since the TCP handshake and slow-start overhead are repeated with every request, latency increases significantly on pages with many resources. At the time, some implementations reused connections using the Keep-Alive extension, but this was not the default behavior of HTTP/1.0.

HTTP/1.1: Connection Reuse Doesn’t Eliminate Wait Times

HTTP/1.1 uses persistent connections by default unless explicitly terminated. Since a single TCP connection is reused for multiple requests, the cost of establishing a connection is reduced.

A single TCP connection is reused, but the order of sending the next request after the response

However, this does not automatically eliminate the wait time between requests. If you send one request, wait until the response is fully received, and then send the next request, the connection remains idle between each round trip.

RTT (Round Trip Time) is the time it takes for a request to travel to the destination and for the response to return. It is used not only to describe the establishment of a TCP connection but also to explain the latency of HTTP requests and responses.

Illustration showing RTT between a client request and a server response

How Pipelining Works

With pipelining, the client sends subsequent requests over the same connection without waiting for the first response.

  1. The client establishes a persistent TCP connection.
  2. The client sends requests 1, 2, and 3 consecutively without waiting for a response.
  3. The server processes the multiple requests.
  4. The server sends responses 1, 2, and 3 in the same order as the requests.

HTTP pipelining: Sending multiple requests consecutively and receiving responses in the same order

Since multiple requests can be squeezed into a single round trip, the theoretical benefit is significant in high-latency environments. However, it is not accurate to simplify the rules regarding methods into a single sentence such as “only idempotent methods are allowed.”

  • The server can process requests for safe methods in parallel.
  • Whether the client can automatically retry if the connection is interrupted depends on idempotency.
  • As a general rule, after sending a non-idempotent request, the client should not pipeline additional requests until it receives the final response. Therefore, while POST is not unconditionally prohibited at the protocol level, it must be handled conservatively because recovery is difficult.

HOL Blocking Caused by Response Order

HTTP/1.1 messages lack a stream identifier that would allow responses to be sent out of order and reassembled. Consequently, even if the server processes requests in parallel, it must send responses in the order they were received.

1. GET /api/complex-report  → 5 seconds
2. GET /images/logo.png     → 10 ms
3. GET /styles.css → 10 ms

Even if the results for requests 2 and 3 are ready first, they cannot be transmitted until the response for request 1 is complete. This phenomenon, where the head of the queue blocks items behind it, is known as HOL (Head-of-Line) blocking in HTTP/1.1 pipelining.

Sequence of HOL blocking: Fast follow-up responses must wait due to a slow first request

It was difficult for browsers and intermediate proxies to implement pipelining consistently, and they also had to determine which requests to safely resend after a connection failure. In practice, opening multiple TCP connections in parallel proved more predictable, and pipelining never became mainstream.

What Did HTTP/2 and HTTP/3 Change?

HTTP/2 divides requests and responses into frames within a single connection and distinguishes them using stream IDs. Even if one stream is slow, response frames from other streams can be sent first, thereby eliminating HTTP/1.1’s application-layer HOL blocking.

However, all streams share a single TCP connection. If a single TCP packet is lost, the streams on that connection may all have to wait together until that packet is retransmitted. This is transport-layer HOL blocking.

HTTP/3 uses QUIC instead of TCP and isolates the transmission state for each stream, reducing the problem where packet loss in one stream blocks other streams.

In summary, the idea of pipelining itself—overlapping multiple tasks without leaving a single connection idle—was correct. The flaw lay in HTTP/1.1’s message structure, which required responses to be sent in order; later versions removed this constraint through stream identification and multiplexing.

References

Leave comment