Skip to content

Commit

Permalink
perf(http2): improve default HTTP2 flow control settings
Browse files Browse the repository at this point in the history
Set default HTTP2 window sizes much larger values than the spec default.

ref #1960
  • Loading branch information
seanmonstar committed Oct 8, 2019
1 parent b4dbad6 commit 2269596
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 15 deletions.
52 changes: 50 additions & 2 deletions benches/end_to_end.rs
Expand Up @@ -11,6 +11,8 @@ use tokio::runtime::current_thread::Runtime;
use hyper::{Body, Method, Request, Response, Server};
use hyper::client::HttpConnector;

// HTTP1

#[bench]
fn http1_get(b: &mut test::Bencher) {
opts()
Expand Down Expand Up @@ -62,6 +64,28 @@ fn http1_parallel_x10_req_10mb(b: &mut test::Bencher) {
.bench(b)
}

#[bench]
fn http1_parallel_x10_res_1mb(b: &mut test::Bencher) {
let body = &[b'x'; 1024 * 1024 * 1];
opts()
.parallel(10)
.response_body(body)
.bench(b)
}

#[bench]
fn http1_parallel_x10_res_10mb(b: &mut test::Bencher) {
let body = &[b'x'; 1024 * 1024 * 10];
opts()
.parallel(10)
.response_body(body)
.bench(b)
}

// HTTP2

const HTTP2_MAX_WINDOW: u32 = std::u32::MAX >> 1;

#[bench]
fn http2_get(b: &mut test::Bencher) {
opts()
Expand Down Expand Up @@ -104,8 +128,32 @@ fn http2_parallel_x10_req_10mb(b: &mut test::Bencher) {
.parallel(10)
.method(Method::POST)
.request_body(body)
.http2_stream_window(std::u32::MAX >> 1)
.http2_conn_window(std::u32::MAX >> 1)
//.http2_stream_window(HTTP2_MAX_WINDOW)
//.http2_conn_window(HTTP2_MAX_WINDOW)
.bench(b)
}

#[bench]
fn http2_parallel_x10_res_1mb(b: &mut test::Bencher) {
let body = &[b'x'; 1024 * 1024 * 1];
opts()
.http2()
.parallel(10)
.response_body(body)
.http2_stream_window(HTTP2_MAX_WINDOW)
.http2_conn_window(HTTP2_MAX_WINDOW)
.bench(b)
}

#[bench]
fn http2_parallel_x10_res_10mb(b: &mut test::Bencher) {
let body = &[b'x'; 1024 * 1024 * 10];
opts()
.http2()
.parallel(10)
.response_body(body)
.http2_stream_window(HTTP2_MAX_WINDOW)
.http2_conn_window(HTTP2_MAX_WINDOW)
.bench(b)
}

Expand Down
21 changes: 18 additions & 3 deletions src/client/conn.rs
Expand Up @@ -34,6 +34,14 @@ type ConnEither<T, B> = Either<
proto::h2::ClientTask<B>,
>;

// Our defaults are chosen for the "majority" case, which usually are not
// resource contrained, and so the spec default of 64kb can be too limiting
// for performance.
const DEFAULT_HTTP2_CONN_WINDOW: u32 = 1024 * 1024 * 5; // 5mb
const DEFAULT_HTTP2_STREAM_WINDOW: u32 = 1024 * 1024 * 2; // 2mb



/// Returns a handshake future over some IO.
///
/// This is a shortcut for `Builder::new().handshake(io)`.
Expand Down Expand Up @@ -425,7 +433,10 @@ impl Builder {
#[inline]
pub fn new() -> Builder {
let mut h2_builder = h2::client::Builder::default();
h2_builder.enable_push(false);
h2_builder
.initial_window_size(DEFAULT_HTTP2_STREAM_WINDOW)
.initial_connection_window_size(DEFAULT_HTTP2_CONN_WINDOW)
.enable_push(false);

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

/// Sets the max connection-level flow control for HTTP2
///
/// Default is 65,535
/// Passing `None` will do nothing.
///
/// If not set, hyper will use a default.
pub fn http2_initial_connection_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {
if let Some(sz) = sz.into() {
self.h2_builder.initial_connection_window_size(sz);
Expand Down
8 changes: 6 additions & 2 deletions src/client/mod.rs
Expand Up @@ -954,7 +954,9 @@ impl Builder {
/// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2
/// stream-level flow control.
///
/// Default is 65,535
/// Passing `None` will do nothing.
///
/// If not set, hyper will use a default.
///
/// [spec]: https://http2.github.io/http2-spec/#SETTINGS_INITIAL_WINDOW_SIZE
pub fn http2_initial_stream_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {
Expand All @@ -964,7 +966,9 @@ impl Builder {

/// Sets the max connection-level flow control for HTTP2
///
/// Default is 65,535
/// Passing `None` will do nothing.
///
/// If not set, hyper will use a default.
pub fn http2_initial_connection_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {
self.conn_builder.http2_initial_connection_window_size(sz.into());
self
Expand Down
28 changes: 23 additions & 5 deletions src/server/conn.rs
Expand Up @@ -37,6 +37,15 @@ pub(super) use self::upgrades::UpgradeableConnection;

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

// Our defaults are chosen for the "majority" case, which usually are not
// resource contrained, and so the spec default of 64kb can be too limiting
// for performance.
//
// At the same time, a server more often has multiple clients connected, and
// so is more likely to use more resources than a client would.
const DEFAULT_HTTP2_CONN_WINDOW: u32 = 1024 * 1024; // 1mb
const DEFAULT_HTTP2_STREAM_WINDOW: u32 = 1024 * 1024; // 1mb

/// A lower-level configuration of the HTTP protocol.
///
/// This structure is used to configure options for an HTTP server connection.
Expand Down Expand Up @@ -178,11 +187,16 @@ impl Http {
/// Creates a new instance of the HTTP protocol, ready to spawn a server or
/// start accepting connections.
pub fn new() -> Http {
let mut h2_builder = h2::server::Builder::default();
h2_builder
.initial_window_size(DEFAULT_HTTP2_STREAM_WINDOW)
.initial_connection_window_size(DEFAULT_HTTP2_CONN_WINDOW);

Http {
exec: Exec::Default,
h1_half_close: true,
h1_writev: true,
h2_builder: h2::server::Builder::default(),
h2_builder,
mode: ConnectionMode::Fallback,
keep_alive: true,
max_buf_size: None,
Expand Down Expand Up @@ -247,7 +261,9 @@ impl<E> Http<E> {
/// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2
/// stream-level flow control.
///
/// Default is 65,535
/// Passing `None` will do nothing.
///
/// If not set, hyper will use a default.
///
/// [spec]: https://http2.github.io/http2-spec/#SETTINGS_INITIAL_WINDOW_SIZE
pub fn http2_initial_stream_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {
Expand All @@ -257,9 +273,11 @@ impl<E> Http<E> {
self
}

/// Sets the max connection-level flow control for HTTP2
/// Sets the max connection-level flow control for HTTP2.
///
/// Passing `None` will do nothing.
///
/// Default is 65,535
/// If not set, hyper will use a default.
pub fn http2_initial_connection_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {
if let Some(sz) = sz.into() {
self.h2_builder.initial_connection_window_size(sz);
Expand All @@ -270,7 +288,7 @@ impl<E> Http<E> {
/// Sets the [`SETTINGS_MAX_CONCURRENT_STREAMS`][spec] option for HTTP2
/// connections.
///
/// Default is no limit (`None`).
/// Default is no limit (`std::u32::MAX`). Passing `None` will do nothing.
///
/// [spec]: https://http2.github.io/http2-spec/#SETTINGS_MAX_CONCURRENT_STREAMS
pub fn http2_max_concurrent_streams(&mut self, max: impl Into<Option<u32>>) -> &mut Self {
Expand Down
10 changes: 7 additions & 3 deletions src/server/mod.rs
Expand Up @@ -306,7 +306,9 @@ impl<I, E> Builder<I, E> {
/// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2
/// stream-level flow control.
///
/// Default is 65,535
/// Passing `None` will do nothing.
///
/// If not set, hyper will use a default.
///
/// [spec]: https://http2.github.io/http2-spec/#SETTINGS_INITIAL_WINDOW_SIZE
pub fn http2_initial_stream_window_size(mut self, sz: impl Into<Option<u32>>) -> Self {
Expand All @@ -316,7 +318,9 @@ impl<I, E> Builder<I, E> {

/// Sets the max connection-level flow control for HTTP2
///
/// Default is 65,535
/// Passing `None` will do nothing.
///
/// If not set, hyper will use a default.
pub fn http2_initial_connection_window_size(mut self, sz: impl Into<Option<u32>>) -> Self {
self.protocol.http2_initial_connection_window_size(sz.into());
self
Expand All @@ -325,7 +329,7 @@ impl<I, E> Builder<I, E> {
/// Sets the [`SETTINGS_MAX_CONCURRENT_STREAMS`][spec] option for HTTP2
/// connections.
///
/// Default is no limit (`None`).
/// Default is no limit (`std::u32::MAX`). Passing `None` will do nothing.
///
/// [spec]: https://http2.github.io/http2-spec/#SETTINGS_MAX_CONCURRENT_STREAMS
pub fn http2_max_concurrent_streams(mut self, max: impl Into<Option<u32>>) -> Self {
Expand Down

0 comments on commit 2269596

Please sign in to comment.