Skip to content

Make HTTP/2 flow control window size configurable for clients and servers #786

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

johnkassebaum
Copy link
Contributor

@johnkassebaum johnkassebaum commented May 8, 2020

Make HTTP/2 flow control target window size configurable in a client or server HTTP2 connection.
Motivation:

Higher streaming thruput between server and client is available by the either specifying a HTTP/2 flow control window size higher than the initial value of 2^16-1. The target value needs to be passed either using SETTINGS_INITIAL_WINDOW_SIZE in the connection preface, or via a WINDOW_UPDATE. As implemented here, the HTTP2FlowControlWindow passes the value configured in a windowUpdate.

Modifications:

For the client:
Added property targetWindowSize to ClientConnection.Configuration.
In the existing ClientConnection.Configuration.init, sets the new targetWindowSize property to the initial flow-control window size (65535).
Duplicated ClientConnection.Configuration.init and added a targetWindowSize arg.
Added property and setter for targetWindowSize to ClientConnection.Builder.
During client bootstrap, pass configuration.targetWindowSize to the channel initializer.
Duplicated channel initializer configureGRPCClient and added a targetWindowSize arg.
Duplicated all tests that directly invoke the original ClientConnection.Configuration.init to explicitly pass targetWindowSizeto the new initializer.

For the server:
Added property httpTargetWindowSize to Server.Configuration.
In Server.Configuration.init, added httpTargetWindowSize arg with default value 2^16-1.
Added property and setter for httpTargetWindowSize to Server.Builder.
During server bootstrap in Server.start, pass configuration.httpTargetWindowSize to the HTTPProtocolSwitcher.
Configure http/2 flow control target window size on the http2 pipeline in HTTPProxySwitcher.
Result:

One can build a ClientConnection or Serverwith a target window size value that is configured via a WINDOW_UPDATE after the connection is established.

@linux-foundation-easycla
Copy link

linux-foundation-easycla bot commented May 8, 2020

CLA Check
The committers are authorized under a signed CLA.

Copy link
Collaborator

@Lukasa Lukasa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Broadly I think this looks really good! We should aim to get a HTTP/2 release out early this week that can unblock this PR.

@@ -31,6 +31,7 @@ extension ClientConnection {
extension ClientConnection {
public class Builder {
private let group: EventLoopGroup
private var targetWindowSize: Int = 65535
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Lukasa should we add a default-target-window-size constant to nio-http2? This is floating around in a number of places.

Alternatively we could just switch the value in the gRPC API to be an optional/enum with "defer to http2" and "use this value" cases.

@glbrntt
Copy link
Collaborator

glbrntt commented May 11, 2020

If you confirm that the correct place is where HTTPProtocolSwitcher.channelRead(context:data:), in the case of .http2, invokes Channel.configureHTTP2Pipeline(mode:) then I would add the same targetWindowSize to Server.Configuration and to Server.Builder, and would then pass it to the HTTPProtocolSwitcher in Server.makeBootstrap(configuration:)

That's the right place 👍

@glbrntt
Copy link
Collaborator

glbrntt commented May 29, 2020

@johnkassebaum FYI your NIO HTTP/2 change was tagged a little while ago

@johnkassebaum
Copy link
Contributor Author

Thanks @glbrntt I saw that. So sorry for the delay on this, was able to get back to it last night and will address comments and add server configuration today.

@johnkassebaum johnkassebaum force-pushed the jk-set-connection-target-window-size branch 3 times, most recently from 8246629 to 65b42eb Compare May 29, 2020 17:24
@johnkassebaum johnkassebaum requested a review from glbrntt May 29, 2020 17:27
@johnkassebaum johnkassebaum marked this pull request as ready for review May 29, 2020 17:27
@johnkassebaum johnkassebaum requested a review from Lukasa May 29, 2020 17:27
@johnkassebaum johnkassebaum force-pushed the jk-set-connection-target-window-size branch from 65b42eb to 5be66d8 Compare May 29, 2020 19:08
Copy link
Collaborator

@glbrntt glbrntt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem about the delay @johnkassebaum! This basically looks good, I just have a couple of comments around docs/naming.

@@ -324,6 +330,7 @@ extension Channel {
}

func configureGRPCClient(
httpTargetWindowSize: Int = 65535,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need a default here: we should have always have a value from the configuration.

@@ -195,6 +197,15 @@ extension ClientConnection.Builder.Secure {
}
}

extension ClientConnection.Builder {
/// Sets the HTTP/2 flow control target window size.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Sets the HTTP/2 flow control target window size.
/// Sets the HTTP/2 flow control target window size. Defaults to 65,535 if not explicitly set.

@@ -18,7 +18,7 @@ Pod::Spec.new do |s|

s.dependency 'Logging', '1.2.0'
s.dependency 'SwiftNIO', '2.15.0'
s.dependency 'SwiftNIOHTTP2', '1.11.0'
s.dependency 'SwiftNIOHTTP2', '1.12.0'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to update this; it's a generated file.

@@ -135,6 +149,43 @@ class ClientTLSFailureTests: GRPCTestCase {
XCTFail("Expected NIOSSLError.handshakeFailed(BoringSSL.sslError)")
}
}

func testClientConnectionFailsWhenServerIsUnknownWithHTTPTargetWindowSize() throws {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you remove the extra tests since we're not actually validating a change in behaviour here? I think I'm okay just deferring to NIO HTTP/2 for the tests.

Copy link
Collaborator

@Lukasa Lukasa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No further notes beyond @glbrntt's.

Package.swift Outdated
@@ -29,7 +29,7 @@ let package = Package(
// Main SwiftNIO package
.package(url: "https://github.com/apple/swift-nio.git", from: "2.14.0"),
// HTTP2 via SwiftNIO
.package(url: "https://github.com/apple/swift-nio-http2.git", from: "1.8.0"),
.package(url: "https://github.com/apple/swift-nio-http2.git", from: "1.12.0"),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mind bumping this to 1.12.1? We missed something the first time with the window size: apple/swift-nio-http2#205

John Kassebaum added 2 commits June 1, 2020 20:50
…connection.

Motivation:

Higher stremaing thruput from server to client is available by specifying a flow control window size higher than the initial value of 2^16-1. The target value needs to be passed either using SETTINGS_INITIAL_WINDOW_SIZE in the connection preface, or via a WINDOW_UPDATE. The HTTP2FlowControlWindow passes the value configured here in `windowUpdate`.

Modifications:

Set package and podspec dependency swift-nio-http2 target to 1.12.0, needed for pipeline configuration with http/2 flow control target window size coniguration.
Added property `httpTargetWindowSize` to `ClientConnection.Configuration`.
In `ClientConnection.Configuration.init`, added httpTargetWindowSize arg with default value 2^16-1.
Added property and setter for `httpTargetWindowSize` to `ClientConnection.Builder`.
During client bootstrap in ConnectionManager, pass `configuration.httpTargetWindowSize` to the channel configurator.
Configure http/2 flow control target window size on the grpc client pipeline.
Duplicated all tests that directly invoke the original `ClientConnection.Configuration.init` to explicitly pass `httpTargetWindowSize` to the new initializer.

Result:

One can build a `ClientConnection` with a http/2 flow control target window size value that is configured via a WINDOW_UPDATE after the connection is established.
…connection.

Motivation:

Higher streaming thruput from client to server is available by specifying a flow control window size higher than the initial value of 2^16-1. The target value needs to be passed either using SETTINGS_INITIAL_WINDOW_SIZE in the connection preface, or via a WINDOW_UPDATE. The HTTP2FlowControlWindow passes the value configured here in `windowUpdate`.

Modifications:
Added property `httpTargetWindowSize` to `Server.Configuration`.
In `Server.Configuration.init`, added httpTargetWindowSize arg with default value 2^16-1.
Added property and setter for `httpTargetWindowSize` to `Server.Builder`.
During server bootstrap in Server.start, pass `configuration.httpTargetWindowSize` to the HTTPProtocolSwitcher.
Configure http/2 flow control target window size on the http2 pipeline in HTTPProxySwitcher.

Result:

One can build a `Server` with a target window size value that is configured via a WINDOW_UPDATE after the connection is established.
@johnkassebaum johnkassebaum force-pushed the jk-set-connection-target-window-size branch from 5be66d8 to c80bd97 Compare June 2, 2020 03:57
@johnkassebaum johnkassebaum requested a review from glbrntt June 2, 2020 04:13
Copy link
Collaborator

@glbrntt glbrntt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thanks @johnkassebaum!

@glbrntt glbrntt merged commit f71049e into grpc:master Jun 2, 2020
@glbrntt glbrntt added the 🆕 semver/minor Adds new public API. label Jun 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🆕 semver/minor Adds new public API.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants