Started as a Microsoft Hackathon 2021 project.
| load | YARP | LLRP_HttpClient | LLRP_LLHTTP | ||
|---|---|---|---|---|---|
| Requests | 9.658.071 | 14.361.795 | +48,70% | 16.104.894 | +66,75% |
| Bad responses | 0 | 0 | 0 | ||
| Mean latency (us) | 792 | 532 | -32,86% | 474 | -40,17% |
| Max latency (us) | 93.781 | 85.050 | -9,31% | 69.737 | -25,64% |
| Requests/sec | 322.349 | 479.094 | +48,63% | 537.287 | +66,68% |
*numbers from aspnet-citrine-lin, using full PGO on .NET 7 preview 3.
dotnet tool update Microsoft.Crank.Controller -g --version "0.2.0-*"
# These require corpnet access for aspnet-citrine-lin
crank --config https://raw.githubusercontent.com/MihaZupan/LLRP/main/benchmarks.yml --profile aspnet-citrine-lin --scenario yarp --json YARP.json --application.framework net7.0
crank --config https://raw.githubusercontent.com/MihaZupan/LLRP/main/benchmarks.yml --profile aspnet-citrine-lin --scenario llrp-httpclient --json LLRP_HttpClient.json
crank --config https://raw.githubusercontent.com/MihaZupan/LLRP/main/benchmarks.yml --profile aspnet-citrine-lin --scenario llrp-llhttp --json LLRP_LLHTTP.json
crank compare YARP.json LLRP_HttpClient.json LLRP_LLHTTP.json
To run the benchmarks with full PGO, append the following to the above commands:
--application.environmentVariables DOTNET_TieredPGO=1 --application.environmentVariables DOTNET_ReadyToRun=0 --application.environmentVariables DOTNET_TC_QuickJitForLoops=1
The following scenarios are available as part of this repository's benchmark definition:
llrp-llhttp: A low-level reverse proxy implementation based on Kestrel platform benchmarks, using LLHTTP as the client for outgoing requests. See LLRPApplication.cs for the implementation.llrp-httpclient: A low-level reverse proxy implementation based on Kestrel platform benchmarks, usingHttpClientas the client for outgoing requests. See HttpClientApplication.cs for the implementation.yarp: A fully-featured microsoft/reverse-proxy benchmark app. Utilizes ASP.NET Core request parsing, routing, connection management and middleware. UsesHttpForwarderfor the proxying, relying onHttpClientfor outgoing requests.HttpClientProxy: A reverse proxy using full ASP.NET Core andHttpClient. See the implementation here.- Differs from
yarpin removing most of the functionality on top of rawHttpClient.SendAsynccalls.
- Differs from
llrp-yarp: A reverse proxy implementation based on Kestrel platform benchmarks that creates customHttpContextand then calls into YARP'sHttpForwarder. See YarpApplication.cs for the implementation.- Differs from
yarpin removing most of ASP.NET Core functionality.
- Differs from
llrp-httpclientwithcontext: Similar tollrp-yarpin that it creates a customHttpContextobject, but then relies onHttpClientfor outgoing requests. See HttpClientWithContextApplication.cs for the implementation.- Differs from
llrp-yarpin removing most of YARP's functionality on top of rawHttpClient.SendAsynccalls. - Differs from
llrp-llhttpin introducing the indirection throughHttpContext, which is part of the cost of using full ASP.NET Core functionality.
- Differs from
haproxy: An HAProxy benchmark used as a performance reference.nginx: An NGINX benchmark used as a performance reference.
Except for yarp, haproxy and nginx, the above benchmarks are minimal implementations, offering minimal functionality, no extensibility or error handling, and may lack in behavioral correctness.
The benchmarks currently allow only cleartext HTTP/1.1 traffic in both directions. Body sizes are not configurable.
llrp-httpclient, llrp-yarp and llrp-httpclientwithcontext scenarios support the following environment variables to configure how HttpClient instances are used:
shareClients: Controls whether theHttpClientinstances are shared between different incoming connections. Defaults tofalse- using a separate client instance for each connection.shareClients.roundRobin: Controls whether a given connection cycles between differentHttpClientinstances between requests. Defaults tofalse- using the same client instance for all requests on the connection.shareClients.count: Controls how manyHttpClientinstances are allocated and shared between all connections. Defaults to1, but has no effect unlessshareClientsis enabled.
Example - running two benchmarks comparing the performance of llrp-httpclient when using 1 vs 2 shared HttpClient instances:
crank --config https://raw.githubusercontent.com/MihaZupan/LLRP/main/benchmarks.yml --profile aspnet-citrine-lin --scenario llrp-httpclient --application.environmentVariables shareClients=true --application.environmentVariables shareClients.count=1 --json LLRP_HttpClient_1.json
crank --config https://raw.githubusercontent.com/MihaZupan/LLRP/main/benchmarks.yml --profile aspnet-citrine-lin --scenario llrp-httpclient --application.environmentVariables shareClients=true --application.environmentVariables shareClients.count=2 --json LLRP_HttpClient_2.json
crank compare LLRP_HttpClient_1.json LLRP_HttpClient_2.json