Skip to content

Commit eb7e583

Browse files
authored
Add option to enable multuple H/3 connections (#1998)
* Add option to enable multuple H/3 connections * Feedback * Fixed typo * Testing - TO BE REVERTED * Revert "Testing - TO BE REVERTED" This reverts commit 326231d.
1 parent 2d04225 commit eb7e583

File tree

6 files changed

+37
-23
lines changed

6 files changed

+37
-23
lines changed

build/httpclient-scenarios.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ parameters:
1919
type: string
2020
default: '--client.framework net9.0 --server.framework net8.0' # net8.0 for server is a temporary workaround
2121

22-
- name: getScenarios
22+
- name: getScenarios
2323
type: object
2424
default:
2525
- displayName: "GET"
2626
arguments: --scenario httpclient-kestrel-get --variable useHttpMessageInvoker=true --property server=kestrel --property client=dotnetinvoker --property method=get --client.options.collectCounters true
2727

28-
- name: postScenarios
28+
- name: postScenarios
2929
type: object
3030
default:
3131
- displayName: "POST"
@@ -41,7 +41,9 @@ parameters:
4141
- displayName: "HTTP/2.0 (mult conn)"
4242
arguments: --variable httpVersion=2.0 --variable useHttps=true --variable http20EnableMultipleConnections=true --property httpversion=h2multconn
4343
- displayName: "HTTP/3.0"
44-
arguments: --variable httpVersion=3.0 --variable useHttps=true --property httpversion=h3
44+
arguments: --variable httpVersion=3.0 --variable useHttps=true --variable http30EnableMultipleConnections=false --property httpversion=h3
45+
- displayName: "HTTP/3.0 (mult conn)"
46+
arguments: --variable httpVersion=3.0 --variable useHttps=true --variable http30EnableMultipleConnections=true --property httpversion=h3multconn
4547

4648
- name: clientsxThreads
4749
type: object

scenarios/README.md

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Continuous benchmarking results are available on [this PowerBI dashboard](https:
88
99
## Requirements
1010

11-
These jobs can be executed using the .NET Crank global tool.
11+
These jobs can be executed using the .NET Crank global tool.
1212
[.NET Core](<http://dot.net>) is required to install the global tool.
1313

1414
Install `crank` with the following command:
@@ -62,7 +62,7 @@ crank --config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenario
6262

6363
### Available scenarios
6464

65-
- `plaintext`: Middleware implementation
65+
- `plaintext`: Middleware implementation
6666
- `https`: Middleware implementation, using HTTPS
6767
- `endpoint`: Middleware implementation with Endpoint routing
6868
- `mvc`: Controller implementation
@@ -85,7 +85,7 @@ crank --config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenario
8585

8686
### Available scenarios
8787

88-
- `json`: Middleware implementation
88+
- `json`: Middleware implementation
8989
- `https`: Middleware implementation, using HTTPS
9090
- `mvc`: Controller implementation
9191
- `mapaction`: Endpoint routing implementation
@@ -125,8 +125,8 @@ The following scenarios are using ASP.NET CORE MVC
125125
- `fortunes_ef_mvc_https`
126126

127127
The suffixes represent different database access strategies:
128-
129-
- No suffix: Raw ADO.NET
128+
129+
- No suffix: Raw ADO.NET
130130
- "ef" suffix: Entity Framework Core
131131
- "dapper" suffix: Dapper
132132

@@ -159,7 +159,7 @@ crank --config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenario
159159

160160
These scenarios are running several web proxies, including [YARP](https://github.com/microsoft/reverse-proxy).
161161

162-
The downstream service returns a variable size content. By default the result is 10 bytes.
162+
The downstream service returns a variable size content. By default the result is 10 bytes.
163163

164164
### Sample
165165

@@ -261,7 +261,7 @@ crank --config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenario
261261
These scenarios measure the performance of different Grpc server and clients implementations.
262262

263263
- Go
264-
- Native (C)
264+
- Native (C)
265265
- ASP.NET
266266

267267
### Sample
@@ -287,13 +287,13 @@ crank --config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenario
287287

288288
#### Arguments
289289

290-
- Number of streams:
290+
- Number of streams:
291291
- `--variable streams=1`
292292
- `--variable streams=70`
293-
- Number of connections:
293+
- Number of connections:
294294
- `--variable connections=1`
295295
- `--variable connections=28`
296-
- Protocol:
296+
- Protocol:
297297
- `--variable protocol=h2`
298298
- `--variable protocol=h3`
299299
- `--variable protocol=h2c`
@@ -345,15 +345,15 @@ crank --config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenario
345345

346346
#### Arguments
347347

348-
- Scenario:
348+
- Scenario:
349349
- `--variable scenario=broadcast`
350350
- `--variable scenario=echo`
351351
- `--variable scenario=echoAll`
352-
- Transport:
352+
- Transport:
353353
- `--variable transport=websockets`
354354
- `--variable transport=serversentevents`
355355
- `--variable transport=longpolling`
356-
- Protocol:
356+
- Protocol:
357357
- `--variable protocol=json`
358358
- `--variable protocol=messagepack`
359359

@@ -397,7 +397,7 @@ crank --config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenario
397397

398398
These scenarios are running various distributed cache benchmarks.
399399

400-
For all the scenarios, the store is initialized with `CacheCount` cache entries. Each request will issue a read or a write based on the `WriteRatio`
400+
For all the scenarios, the store is initialized with `CacheCount` cache entries. Each request will issue a read or a write based on the `WriteRatio`
401401
argument choosing a key randomly. The HTTP response won't contain the cache entry data so that it doesn't impact the raw store perf measurement.
402402

403403
### Sample
@@ -512,6 +512,9 @@ crank --config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenario
512512
- Enable multiple HTTP/2.0 connections:
513513
- `--variable http20EnableMultipleConnections=true` (default)
514514
- `--variable http20EnableMultipleConnections=false`
515+
- Enable multiple HTTP/3.0 connections (from .NET 9.0):
516+
- `--variable http30EnableMultipleConnections=true` (default)
517+
- `--variable http30EnableMultipleConnections=false`
515518
- Whether to use WinHttpHandler instead of SocketsHttpHandler:
516519
- `--variable useWinHttpHandler=false` (default)
517520
- `--variable useWinHttpHandler=true` -- *requires Windows*
@@ -538,7 +541,7 @@ These scenarios provide benchmarks to help improve the performance of the .NET G
538541
### Sample
539542

540543
```
541-
crank --config https://raw.githubusercontent.com/dotnet/performance/main/src/benchmarks/gc/scenarios/CrankConfiguration.yaml --scenario 2gb-pinning --profile aspnet-citrine-win --application.framework net9.0
544+
crank --config https://raw.githubusercontent.com/dotnet/performance/main/src/benchmarks/gc/scenarios/CrankConfiguration.yaml --scenario 2gb-pinning --profile aspnet-citrine-win --application.framework net9.0
542545
```
543546
### Available scenarios
544547

scenarios/httpclient.benchmarks.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ variables:
2525
# HttpClient-specific parameters:
2626
http11MaxConnectionsPerServer: 0 #unlimited
2727
http20EnableMultipleConnections: true
28+
http30EnableMultipleConnections: true
2829
useWinHttpHandler: false
2930
useHttpMessageInvoker: false
3031
useDefaultRequestHeaders: false
@@ -102,6 +103,7 @@ scenarios:
102103
numberOfHttpClients: 1
103104
concurrencyPerHttpClient: '{% if cores > 0 %}{{cores}}{% else %}1{% endif %}'
104105
http20EnableMultipleConnections: false
106+
http30EnableMultipleConnections: false
105107
useHttpMessageInvoker: true
106108
host: '{{secondaryAddress}}'
107109

@@ -168,7 +170,7 @@ jobs:
168170
isConsoleApp: true
169171
waitForExit: true
170172
timeout: 1200 #seconds
171-
arguments: '--address {{host}} --port {{serverPort}} --useHttps {{useHttps}} --path /{{scenario}} --scenario {{scenario}} --httpVersion {{httpVersion}} --numberOfHttpClients {{numberOfHttpClients}} --concurrencyPerHttpClient {{concurrencyPerHttpClient}} --http11MaxConnectionsPerServer {{http11MaxConnectionsPerServer}} --http20EnableMultipleConnections {{http20EnableMultipleConnections}} --useWinHttpHandler {{useWinHttpHandler}} --useHttpMessageInvoker {{useHttpMessageInvoker}} --collectRequestTimings {{collectRequestTimings}} --contentSize {{requestContentSize}} --contentWriteSize {{requestContentWriteSize}} --contentFlushAfterWrite {{requestContentFlushAfterWrite}} --contentUnknownLength {{requestContentUnknownLength}} {{headersDictionary[requestHeaders]}} --generatedStaticHeadersCount {{generatedStaticRequestHeadersCount}} --generatedDynamicHeadersCount {{generatedDynamicRequestHeadersCount}} --useDefaultRequestHeaders {{useDefaultRequestHeaders}} --warmup {{warmup}} --duration {{duration}}'
173+
arguments: '--address {{host}} --port {{serverPort}} --useHttps {{useHttps}} --path /{{scenario}} --scenario {{scenario}} --httpVersion {{httpVersion}} --numberOfHttpClients {{numberOfHttpClients}} --concurrencyPerHttpClient {{concurrencyPerHttpClient}} --http11MaxConnectionsPerServer {{http11MaxConnectionsPerServer}} --http20EnableMultipleConnections {{http20EnableMultipleConnections}} --http30EnableMultipleConnections {{http30EnableMultipleConnections}} --useWinHttpHandler {{useWinHttpHandler}} --useHttpMessageInvoker {{useHttpMessageInvoker}} --collectRequestTimings {{collectRequestTimings}} --contentSize {{requestContentSize}} --contentWriteSize {{requestContentWriteSize}} --contentFlushAfterWrite {{requestContentFlushAfterWrite}} --contentUnknownLength {{requestContentUnknownLength}} {{headersDictionary[requestHeaders]}} --generatedStaticHeadersCount {{generatedStaticRequestHeadersCount}} --generatedDynamicHeadersCount {{generatedDynamicRequestHeadersCount}} --useDefaultRequestHeaders {{useDefaultRequestHeaders}} --warmup {{warmup}} --duration {{duration}}'
172174

173175
wrk:
174176
source:

src/BenchmarksApps/HttpClientBenchmarks/Clients/HttpClient/ClientOptions.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public class ClientOptions
1818
public int ConcurrencyPerHttpClient { get; set; }
1919
public int Http11MaxConnectionsPerServer { get; set; }
2020
public bool Http20EnableMultipleConnections { get; set; }
21+
public bool Http30EnableMultipleConnections { get; set; }
2122
public bool UseWinHttpHandler { get; set; }
2223
public bool UseHttpMessageInvoker { get; set; }
2324
public bool CollectRequestTimings { get; set; }
@@ -37,9 +38,9 @@ public override string ToString()
3738
{
3839
return $"Address={Address}; Port={Port}; UseHttps={UseHttps}; Path={Path}; HttpVersion={HttpVersion}; NumberOfHttpClients={NumberOfHttpClients}; " +
3940
$"ConcurrencyPerHttpClient={ConcurrencyPerHttpClient}; Http11MaxConnectionsPerServer={Http11MaxConnectionsPerServer}; " +
40-
$"Http20EnableMultipleConnections={Http20EnableMultipleConnections}; UseWinHttpHandler={UseWinHttpHandler}; " +
41-
$"UseHttpMessageInvoker={UseHttpMessageInvoker}; CollectRequestTimings={CollectRequestTimings}; Scenario={Scenario}; " +
42-
$"ContentSize={ContentSize}; ContentWriteSize={ContentWriteSize}; ContentFlushAfterWrite={ContentFlushAfterWrite}; " +
41+
$"Http20EnableMultipleConnections={Http20EnableMultipleConnections}; Http30EnableMultipleConnections={Http30EnableMultipleConnections}; " +
42+
$"UseWinHttpHandler={UseWinHttpHandler}; UseHttpMessageInvoker={UseHttpMessageInvoker}; CollectRequestTimings={CollectRequestTimings}; " +
43+
$"Scenario={Scenario}; ContentSize={ContentSize}; ContentWriteSize={ContentWriteSize}; ContentFlushAfterWrite={ContentFlushAfterWrite}; " +
4344
$"ContentUnknownLength={ContentUnknownLength}; Headers=[{string.Join(", ", Headers.Select(h => $"\"{h.Name}: {h.Value}\""))}]; " +
4445
$"GeneratedStaticHeadersCount={GeneratedStaticHeadersCount}; GeneratedDynamicHeadersCount={GeneratedDynamicHeadersCount}; " +
4546
$"UseDefaultRequestHeaders={UseDefaultRequestHeaders}; Warmup={Warmup}; Duration={Duration}";

src/BenchmarksApps/HttpClientBenchmarks/Clients/HttpClient/ClientOptionsBinder.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public class ClientOptionsBinder : BinderBase<ClientOptions>
1515
public static Option<int> ConcurrencyPerHttpClientOption { get; } = new Option<int>("--concurrencyPerHttpClient", () => 1, "Number of concurrect requests per one HttpClient");
1616
public static Option<int> Http11MaxConnectionsPerServerOption { get; } = new Option<int>("--http11MaxConnectionsPerServer", () => 0, "Max number of HTTP/1.1 connections per server, 0 for unlimited");
1717
public static Option<bool> Http20EnableMultipleConnectionsOption { get; } = new Option<bool>("--http20EnableMultipleConnections", () => true, "Enable multiple HTTP/2.0 connections");
18+
public static Option<bool> Http30EnableMultipleConnectionsOption { get; } = new Option<bool>("--http30EnableMultipleConnections", () => true, "Enable multiple HTTP/3.0 connections");
1819
public static Option<bool> UseWinHttpHandlerOption { get; } = new Option<bool>("--useWinHttpHandler", () => false, "Use WinHttpHandler instead of SocketsHttpHandler");
1920
public static Option<bool> UseHttpMessageInvokerOption { get; } = new Option<bool>("--useHttpMessageInvoker", () => false, "Use HttpMessageInvoker instead of HttpClient");
2021
public static Option<bool> CollectRequestTimingsOption { get; } = new Option<bool>("--collectRequestTimings", () => false, "Collect percentiled metrics of request timings");
@@ -41,6 +42,7 @@ public static void AddOptionsToCommand(RootCommand command)
4142
command.AddOption(ConcurrencyPerHttpClientOption);
4243
command.AddOption(Http11MaxConnectionsPerServerOption);
4344
command.AddOption(Http20EnableMultipleConnectionsOption);
45+
command.AddOption(Http30EnableMultipleConnectionsOption);
4446
command.AddOption(UseWinHttpHandlerOption);
4547
command.AddOption(UseHttpMessageInvokerOption);
4648
command.AddOption(CollectRequestTimingsOption);
@@ -72,6 +74,7 @@ protected override ClientOptions GetBoundValue(BindingContext bindingContext)
7274
ConcurrencyPerHttpClient = parsed.GetValueForOption(ConcurrencyPerHttpClientOption),
7375
Http11MaxConnectionsPerServer = parsed.GetValueForOption(Http11MaxConnectionsPerServerOption),
7476
Http20EnableMultipleConnections = parsed.GetValueForOption(Http20EnableMultipleConnectionsOption),
77+
Http30EnableMultipleConnections = parsed.GetValueForOption(Http30EnableMultipleConnectionsOption),
7578
UseWinHttpHandler = parsed.GetValueForOption(UseWinHttpHandlerOption),
7679
UseHttpMessageInvoker = parsed.GetValueForOption(UseHttpMessageInvokerOption),
7780
CollectRequestTimings = parsed.GetValueForOption(CollectRequestTimingsOption),

src/BenchmarksApps/HttpClientBenchmarks/Clients/HttpClient/Program.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ private static async Task Setup()
129129
SslOptions = new SslClientAuthenticationOptions { RemoteCertificateValidationCallback = delegate { return true; } },
130130
MaxConnectionsPerServer = max11ConnectionsPerServer,
131131
EnableMultipleHttp2Connections = s_options.Http20EnableMultipleConnections,
132+
#if NET9_0_OR_GREATER
133+
EnableMultipleHttp3Connections = s_options.Http30EnableMultipleConnections,
134+
#endif
132135
ConnectTimeout = Timeout.InfiniteTimeSpan,
133136
};
134137
}
@@ -396,7 +399,7 @@ private static void CreateRequestContentData()
396399
}
397400

398401
private static HttpRequestMessage CreateRequest(HttpMethod method, Uri uri) =>
399-
new HttpRequestMessage(method, uri) {
402+
new HttpRequestMessage(method, uri) {
400403
Version = s_options.HttpVersion!,
401404
VersionPolicy = HttpVersionPolicy.RequestVersionExact
402405
};

0 commit comments

Comments
 (0)