.NET 6, HTTP3 and QUIC
Microsoft introduced HTTP/3 support into .NET 6 preview to allow customers to start experimenting with the new protocol within the .NET 6 timeframe. HTTP3 is enabled by support for the new QUIC protocol in .NET 6 using the MSQuic library.
To appreciate what this means we need to take a little step back through the history of the HTTP protocol.
The History Part
Figure 1 illustrates the differences between the HTTP 1.1, 2 and 3 protocols and tries to highlight what each one brings to the table.
In HTTP1.1 every request/response stream was handled by an entirely new TCP connection. This means that TLS is set up for every new connection that comes in. The TLS protocol has some overhead cost associated with establishing a secure connection. You can see with this large overhead cost how multiple requests can quickly overwhelm the server resources and slow things down.
Google introduced the experimental SPDY protocol to browsers back in 2012. This new protocol ended up being the basis for the HTTP2 protocol published in 2015, which focused on improving the overall performance of HTTP over HTTP/1.1.
To achieve the goal of performance improvement HTTP2 introduced a new binary framing layer that allowed the HTTP stream to be split up into multiple frames and sent across the same TCP connection. This massively reduced the overhead of setting up a new TCP connection for every request (including the TLS setup) and as such allowed multiple requests to run in parallel over a single connection.
HTTP/2 was a great improvement over HTTP/1.1 but there was still a limitation in its design. HTTP/2 still used the TCP protocol. TCP is designed to be fault tolerant from the ground up. This means that TCP is designed to recover from lost packets during the transmission of data. The problem however is that these lost data packets have a tendency to block the TCP connection while the server resends the lost data. This blocking mechanism slows the connection down and throughput can be affected. This is called “head of line blocking”. Enter QUIC
QUIC is a brand new protocol which unlike TCP doesn’t block the request stream when encountering lost packets. QUIC uses UDP instead of TCP and builds top of HTTP/2’s multiplexing capability. UDP is a protocol that supports faster throughput than TCP, as UDP doesn’t have the ability to recover from lost packets built into the protocol. This means QUIC can take a more modern approach to handling lost packets than TCP. All this means that HTTP/3 can vastly improve server performance.
So what about .NET 6?
- Lets create a new server project
- We need to update our .csproj to enable the preview features
- We now configure the Kestrel server to support HTTP3. Our Program.cs file looks like this
- We should be able to run the server now with dotnet run
- Now we can create our client project
- We need to modify our .csproj to enable HTTP3 support
- We can now use HttpClient to call our server with the following code:
- Running our client should give us the following result:
And that’s how we use HTTP3 in .NET 6!
The example code is available at this repo https://github.com/leedale1981/dotnet6-http3
- Here is a great video on HTTP3 and QUIC
- .NET Blog discussion on HTTP3 in .NET 6 https://devblogs.microsoft.com/dotnet/http-3-support-in-dotnet-6/
- Microsoft MSQuic library https://github.com/microsoft/msquic
- Facebook Engineering post https://engineering.fb.com/2020/10/21/networking-traffic/how-facebook-is-bringing-quic-to-billions/