most often, it helps when there are multiple logical connections muxed over a single physical connection
most often, it helps when there are multiple logical connections muxed over a single physical connection
In real life, browsers open up to four to six HTTP 1.1 connections and maintain them for pipelining. You can increase that number to pretty much anything and enjoy a web full of "permission denied" pages, timeouts and IP bans. I did that for a while when I followed one of those "how to make Firefox faster" guides as a kid, cannot recommend.
That's also four to six three way handshakes, each taking several hundred milliseconds to complete with a risk of failure and retrying, most of which are pretty meaningless, with a hard limit on the amount of individual files one can request at the same time. You'll also have to deal with the traffic congestion engine kicking in multiple times when the WiFi connection degrades. There's also no real way to bypass the TCP slow start for every connection, so you'd better have an excellent connection available or you're artificially restricting your throughput when those streams suddenly start delivering data.
The inline mixing of HTTP/2 removes a whole bunch of restrictions. There are still a bunch of restrictions that only got fixed in HTTP/3 but there's no doubt that HTTP connections improved when HTTP/2 came about.
request-per-connection is a nice, simple, but ultimately naïve model for network communication
All a connection is doing is managing the state of a given byte stream, keeping track of how much was sent on one end and received on the other end. All the packets for all connections go through the same pipes and are even routed the same. The TCP stack sees an IP packet coming in, and in its IP and TCP headers it sees it's from IP:port, so it maps it to the state it is maintaining for that source.
HTTP/3 is using UDP, which is inherently connectionless, but is implementing its own logic of multiple streams/connections. It is not doing anything sensibly different.
"the state it is maintaining for that source" is the "discrete" thing I'm referring to
creating that state requires at least one network round-trip to the remote, and incurs non-negligible costs on the local machine in the application, network, system, and kernel layers
those costs define a per-connection overhead which are almost immediately the main performance bottleneck in systems that do connection-per-request
those costs amortize to zero if you multiplex requests over a single connection
Http/1 Keep-Alive was one the earliest protocol performance improvement. It meant the TCP connection could be reused for the next resource, avoiding the overhead if closing and reopening a new connection for every request to the same server.
You can see http/2 multiplexing as a natural evolution to the keep alive. Instead of doing every request sequentially, just send everything you need at once and let the server figure out in which order to process everything.
Concurrent TCP connections do have an impact on all stateful firewalls in your path, stateful load balancers and of course the server itself. A client that opens dozens of simultaneous TCP to request all the resources on a page all at once would be frowned upon, and quickly hit rate-limits and anti-abuse protections. You can call it ossification of protocols but that is the situation even google could not workaround when specifying http/2 and then quic.
Probably they are referring to head of line blocking: https://en.wikipedia.org/wiki/Head-of-line_blocking
But I suppose it's common for web people to have no idea how networking actually works.
https://web.dev/performance-http2/
With HTTP/1.x, if the client wants to make multiple
parallel requests to improve performance, then multiple TCP
connections must be used (see Using Multiple TCP
Connections ). This behavior is a direct consequence of the
HTTP/1.x delivery model, which ensures that only one
response can be delivered at a time (response queuing) per
connection. Worse, this also results in head-of-line
blocking and inefficient use of the underlying TCP
connection.
The new binary framing layer in HTTP/2 removes these
limitations, and enables full request and response
multiplexing, by allowing the client and server to break
down an HTTP message into independent frames, interleave
them, and then reassemble them on the other end.
it very often makes sense "to do that"As it says in the thing you quoted, the correct approach is to use multiple TCP connections.
The only advantage of HTTP/3 over that is that it only pays for the latency overhead of connection establishment once instead of once per stream. This is a very small optimization that is only relevant in a very narrow set of cases.
making 10 concurrent HTTP GET requests to the same server should not require you to make 10 connections to that server
muxing multiple logical connections/streams over a single physical connection is, like, networking 101 type stuff
you're out of your element donny, go home