Steve Gordon published great post describing the history of HttpClient, its evolution (WinHttpHandler, SocketHttpHandler, etc.) and the connection pooling details under the HttpClient in .NET Core.
I was interested especially in the connection pooling with HTTP/2. .NET Core brings HTTP/2 support (together with TLS support). For more details see: https://docs.microsoft.com/en-us/dotnet/core/whats-new/dotnet-core-3-0#http2-support
Unfortunately, all the connection pooling tests and details mentioned in Steve’s blog are applying only to HTTP 1.1 and not to HTTP2.
I’ll cover HTTP2 in this blog post.
Show me the code!
I built the sample .NET Core application based on the code from Steve’s post. I changed it to display IP(v4,v6) addresses and mainly to use HTTP/2.
As you can see, I try to set MaxConnectionsPerServer to 20. The program also outputs a IPv4 as well as IPv6 address retrieved from DNS.
Starting, press a key to continue ... 2a00:1450:4014:80c::2004 188.8.131.52 Press a key to exit...
I do the same as Steve did to check what connections are open using netstat command.
netstat -ano | findstr 2a00:1450:4014:80c::2004
The result is:
TCP [2a00:...:e4e1]:5472 [2a00:1450:4014:80c::2004]:443 ESTABLISHED 19744
As you can see, in case of HTTP2, there is only 1 connection created. The settings I tried to apply are only for HTTP1.1. Sending the messages (streams) over 1 connection has its own limitations. RFC defines at least 100 streams over 1 connection. By default, in .NET Core implementation the number of concurrent streams transferred over 1 connection is int.Max (see the code Http2Connection.cs#L118) unless adjusted by the server using settings frame (Http2Connection.cs#L470).
We run our services in high volume scenarios. We need the connection pooling together with Http/2 support, adjusting maximum number of streams, etc. If you know about any implementation covering this, please, let me know.
Let’s deep dive little bit
Let’s deep dive into the code proving the theory about 1 connection. The class responsible for creating connections is Http2Connection.cs
The observability is built-inside the code using TraceSource. Let’s look under-the-hood what’s going on.
Steps to do:
- Run the netcore application
- Run dotnet-trace ps to list the processes and its IDs
21104 Http2NetCoreApp .....\bin\Debug\netcoreapp3.1\Http2NetCoreApp.exe
- Run dotnet-trace collect –process-id 21104 –providers Microsoft-System-Net-Http
- Move on with the application (hit Enter in netcoreapp)
- Switch to the tracing window, the trace recording is in progress.
- Once the netcore application is done, close it (hit Enter)
- Recording the trace finished. The whole trace is stored into a file with nettrace suffix.
Provider Name Keywords Level Enabled By Microsoft-System-Net-Http 0xFFFFFFFFFFFFFFFF Verbose(5) --providers Process : .....\bin\Debug\netcoreapp3.1\Http2NetCoreApp.exe Output File : C:\temp\http2netcoreapp\trace.nettrace [00:00:00:22] Recording trace 2.4378 (MB) Press or <Ctrl+C> to exit... Trace completed.
Let’s see what’s inside. We can inspect it with perfview!
- Download, run perfview and open the nettrace file.
- Navigate into “Events”.
- Double-click the event Microsoft-System-Net-Http/HandlerMessage to see the events with this name. Pay attention to column called Rest.
This column contains all custom event details. After inspecting it you can find out that there is only 1 event with message “Attempting new HTTP2 connection.”
That’s all for now.