Skip to content

Commit 2269596

Browse files
committed
perf(http2): improve default HTTP2 flow control settings
Set default HTTP2 window sizes much larger values than the spec default. ref #1960
1 parent b4dbad6 commit 2269596

File tree

5 files changed

+104
-15
lines changed

5 files changed

+104
-15
lines changed

benches/end_to_end.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use tokio::runtime::current_thread::Runtime;
1111
use hyper::{Body, Method, Request, Response, Server};
1212
use hyper::client::HttpConnector;
1313

14+
// HTTP1
15+
1416
#[bench]
1517
fn http1_get(b: &mut test::Bencher) {
1618
opts()
@@ -62,6 +64,28 @@ fn http1_parallel_x10_req_10mb(b: &mut test::Bencher) {
6264
.bench(b)
6365
}
6466

67+
#[bench]
68+
fn http1_parallel_x10_res_1mb(b: &mut test::Bencher) {
69+
let body = &[b'x'; 1024 * 1024 * 1];
70+
opts()
71+
.parallel(10)
72+
.response_body(body)
73+
.bench(b)
74+
}
75+
76+
#[bench]
77+
fn http1_parallel_x10_res_10mb(b: &mut test::Bencher) {
78+
let body = &[b'x'; 1024 * 1024 * 10];
79+
opts()
80+
.parallel(10)
81+
.response_body(body)
82+
.bench(b)
83+
}
84+
85+
// HTTP2
86+
87+
const HTTP2_MAX_WINDOW: u32 = std::u32::MAX >> 1;
88+
6589
#[bench]
6690
fn http2_get(b: &mut test::Bencher) {
6791
opts()
@@ -104,8 +128,32 @@ fn http2_parallel_x10_req_10mb(b: &mut test::Bencher) {
104128
.parallel(10)
105129
.method(Method::POST)
106130
.request_body(body)
107-
.http2_stream_window(std::u32::MAX >> 1)
108-
.http2_conn_window(std::u32::MAX >> 1)
131+
//.http2_stream_window(HTTP2_MAX_WINDOW)
132+
//.http2_conn_window(HTTP2_MAX_WINDOW)
133+
.bench(b)
134+
}
135+
136+
#[bench]
137+
fn http2_parallel_x10_res_1mb(b: &mut test::Bencher) {
138+
let body = &[b'x'; 1024 * 1024 * 1];
139+
opts()
140+
.http2()
141+
.parallel(10)
142+
.response_body(body)
143+
.http2_stream_window(HTTP2_MAX_WINDOW)
144+
.http2_conn_window(HTTP2_MAX_WINDOW)
145+
.bench(b)
146+
}
147+
148+
#[bench]
149+
fn http2_parallel_x10_res_10mb(b: &mut test::Bencher) {
150+
let body = &[b'x'; 1024 * 1024 * 10];
151+
opts()
152+
.http2()
153+
.parallel(10)
154+
.response_body(body)
155+
.http2_stream_window(HTTP2_MAX_WINDOW)
156+
.http2_conn_window(HTTP2_MAX_WINDOW)
109157
.bench(b)
110158
}
111159

src/client/conn.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ type ConnEither<T, B> = Either<
3434
proto::h2::ClientTask<B>,
3535
>;
3636

37+
// Our defaults are chosen for the "majority" case, which usually are not
38+
// resource contrained, and so the spec default of 64kb can be too limiting
39+
// for performance.
40+
const DEFAULT_HTTP2_CONN_WINDOW: u32 = 1024 * 1024 * 5; // 5mb
41+
const DEFAULT_HTTP2_STREAM_WINDOW: u32 = 1024 * 1024 * 2; // 2mb
42+
43+
44+
3745
/// Returns a handshake future over some IO.
3846
///
3947
/// This is a shortcut for `Builder::new().handshake(io)`.
@@ -425,7 +433,10 @@ impl Builder {
425433
#[inline]
426434
pub fn new() -> Builder {
427435
let mut h2_builder = h2::client::Builder::default();
428-
h2_builder.enable_push(false);
436+
h2_builder
437+
.initial_window_size(DEFAULT_HTTP2_STREAM_WINDOW)
438+
.initial_connection_window_size(DEFAULT_HTTP2_CONN_WINDOW)
439+
.enable_push(false);
429440

430441
Builder {
431442
exec: Exec::Default,
@@ -486,7 +497,9 @@ impl Builder {
486497
/// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2
487498
/// stream-level flow control.
488499
///
489-
/// Default is 65,535
500+
/// Passing `None` will do nothing.
501+
///
502+
/// If not set, hyper will use a default.
490503
///
491504
/// [spec]: https://http2.github.io/http2-spec/#SETTINGS_INITIAL_WINDOW_SIZE
492505
pub fn http2_initial_stream_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {
@@ -498,7 +511,9 @@ impl Builder {
498511

499512
/// Sets the max connection-level flow control for HTTP2
500513
///
501-
/// Default is 65,535
514+
/// Passing `None` will do nothing.
515+
///
516+
/// If not set, hyper will use a default.
502517
pub fn http2_initial_connection_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {
503518
if let Some(sz) = sz.into() {
504519
self.h2_builder.initial_connection_window_size(sz);

src/client/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -954,7 +954,9 @@ impl Builder {
954954
/// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2
955955
/// stream-level flow control.
956956
///
957-
/// Default is 65,535
957+
/// Passing `None` will do nothing.
958+
///
959+
/// If not set, hyper will use a default.
958960
///
959961
/// [spec]: https://http2.github.io/http2-spec/#SETTINGS_INITIAL_WINDOW_SIZE
960962
pub fn http2_initial_stream_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {
@@ -964,7 +966,9 @@ impl Builder {
964966

965967
/// Sets the max connection-level flow control for HTTP2
966968
///
967-
/// Default is 65,535
969+
/// Passing `None` will do nothing.
970+
///
971+
/// If not set, hyper will use a default.
968972
pub fn http2_initial_connection_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {
969973
self.conn_builder.http2_initial_connection_window_size(sz.into());
970974
self

src/server/conn.rs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,15 @@ pub(super) use self::upgrades::UpgradeableConnection;
3737

3838
#[cfg(feature = "tcp")] pub use super::tcp::{AddrIncoming, AddrStream};
3939

40+
// Our defaults are chosen for the "majority" case, which usually are not
41+
// resource contrained, and so the spec default of 64kb can be too limiting
42+
// for performance.
43+
//
44+
// At the same time, a server more often has multiple clients connected, and
45+
// so is more likely to use more resources than a client would.
46+
const DEFAULT_HTTP2_CONN_WINDOW: u32 = 1024 * 1024; // 1mb
47+
const DEFAULT_HTTP2_STREAM_WINDOW: u32 = 1024 * 1024; // 1mb
48+
4049
/// A lower-level configuration of the HTTP protocol.
4150
///
4251
/// This structure is used to configure options for an HTTP server connection.
@@ -178,11 +187,16 @@ impl Http {
178187
/// Creates a new instance of the HTTP protocol, ready to spawn a server or
179188
/// start accepting connections.
180189
pub fn new() -> Http {
190+
let mut h2_builder = h2::server::Builder::default();
191+
h2_builder
192+
.initial_window_size(DEFAULT_HTTP2_STREAM_WINDOW)
193+
.initial_connection_window_size(DEFAULT_HTTP2_CONN_WINDOW);
194+
181195
Http {
182196
exec: Exec::Default,
183197
h1_half_close: true,
184198
h1_writev: true,
185-
h2_builder: h2::server::Builder::default(),
199+
h2_builder,
186200
mode: ConnectionMode::Fallback,
187201
keep_alive: true,
188202
max_buf_size: None,
@@ -247,7 +261,9 @@ impl<E> Http<E> {
247261
/// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2
248262
/// stream-level flow control.
249263
///
250-
/// Default is 65,535
264+
/// Passing `None` will do nothing.
265+
///
266+
/// If not set, hyper will use a default.
251267
///
252268
/// [spec]: https://http2.github.io/http2-spec/#SETTINGS_INITIAL_WINDOW_SIZE
253269
pub fn http2_initial_stream_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {
@@ -257,9 +273,11 @@ impl<E> Http<E> {
257273
self
258274
}
259275

260-
/// Sets the max connection-level flow control for HTTP2
276+
/// Sets the max connection-level flow control for HTTP2.
277+
///
278+
/// Passing `None` will do nothing.
261279
///
262-
/// Default is 65,535
280+
/// If not set, hyper will use a default.
263281
pub fn http2_initial_connection_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {
264282
if let Some(sz) = sz.into() {
265283
self.h2_builder.initial_connection_window_size(sz);
@@ -270,7 +288,7 @@ impl<E> Http<E> {
270288
/// Sets the [`SETTINGS_MAX_CONCURRENT_STREAMS`][spec] option for HTTP2
271289
/// connections.
272290
///
273-
/// Default is no limit (`None`).
291+
/// Default is no limit (`std::u32::MAX`). Passing `None` will do nothing.
274292
///
275293
/// [spec]: https://http2.github.io/http2-spec/#SETTINGS_MAX_CONCURRENT_STREAMS
276294
pub fn http2_max_concurrent_streams(&mut self, max: impl Into<Option<u32>>) -> &mut Self {

src/server/mod.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,9 @@ impl<I, E> Builder<I, E> {
306306
/// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2
307307
/// stream-level flow control.
308308
///
309-
/// Default is 65,535
309+
/// Passing `None` will do nothing.
310+
///
311+
/// If not set, hyper will use a default.
310312
///
311313
/// [spec]: https://http2.github.io/http2-spec/#SETTINGS_INITIAL_WINDOW_SIZE
312314
pub fn http2_initial_stream_window_size(mut self, sz: impl Into<Option<u32>>) -> Self {
@@ -316,7 +318,9 @@ impl<I, E> Builder<I, E> {
316318

317319
/// Sets the max connection-level flow control for HTTP2
318320
///
319-
/// Default is 65,535
321+
/// Passing `None` will do nothing.
322+
///
323+
/// If not set, hyper will use a default.
320324
pub fn http2_initial_connection_window_size(mut self, sz: impl Into<Option<u32>>) -> Self {
321325
self.protocol.http2_initial_connection_window_size(sz.into());
322326
self
@@ -325,7 +329,7 @@ impl<I, E> Builder<I, E> {
325329
/// Sets the [`SETTINGS_MAX_CONCURRENT_STREAMS`][spec] option for HTTP2
326330
/// connections.
327331
///
328-
/// Default is no limit (`None`).
332+
/// Default is no limit (`std::u32::MAX`). Passing `None` will do nothing.
329333
///
330334
/// [spec]: https://http2.github.io/http2-spec/#SETTINGS_MAX_CONCURRENT_STREAMS
331335
pub fn http2_max_concurrent_streams(mut self, max: impl Into<Option<u32>>) -> Self {

0 commit comments

Comments
 (0)