From 3a27000022c8bcf034115d91c8cd0e14b44ab0b6 Mon Sep 17 00:00:00 2001 From: Idel Pivnitskiy Date: Mon, 3 May 2021 16:18:17 -0700 Subject: [PATCH 1/2] Use `UniformStreamByteDistributor` for HTTP/2 connections Motivation: HTTP/2 spec defines priorities for streams. However, in ST we do not expose API to assign priorities for streams and this features is rarely used in general. `Http2FrameCodecBuilder` creates connections with `WeightedFairQueueByteDistributor` by default that takes priorities into account. We can use `UniformStreamByteDistributor` to reduce overhead of managing HTTP/2 streams. Modifications: - Extend `Http2FrameCodecBuilder` to use `UniformStreamByteDistributor` for new `Http2Connection`(s); Result: Less CPU usage for HTTP/2 ~1-1.5% according to the benchmarks. --- gradle.properties | 2 +- .../H2ClientParentChannelInitializer.java | 5 +- .../H2ServerParentChannelInitializer.java | 5 +- .../OptimizedHttp2FrameCodecBuilder.java | 55 +++++++++++++++++++ 4 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 servicetalk-http-netty/src/main/java/io/servicetalk/http/netty/OptimizedHttp2FrameCodecBuilder.java diff --git a/gradle.properties b/gradle.properties index fc9ecc707d..a5320a717f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,7 +17,7 @@ group=io.servicetalk version=0.40.0-SNAPSHOT -nettyVersion=4.1.63.Final +nettyVersion=4.1.64.Final-SNAPSHOT tcnativeVersion=2.0.38.Final jsr305Version=3.0.2 diff --git a/servicetalk-http-netty/src/main/java/io/servicetalk/http/netty/H2ClientParentChannelInitializer.java b/servicetalk-http-netty/src/main/java/io/servicetalk/http/netty/H2ClientParentChannelInitializer.java index 2ac45c60c2..564c8fe090 100644 --- a/servicetalk-http-netty/src/main/java/io/servicetalk/http/netty/H2ClientParentChannelInitializer.java +++ b/servicetalk-http-netty/src/main/java/io/servicetalk/http/netty/H2ClientParentChannelInitializer.java @@ -1,5 +1,5 @@ /* - * Copyright © 2019-2020 Apple Inc. and the ServiceTalk project authors + * Copyright © 2019-2021 Apple Inc. and the ServiceTalk project authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,6 @@ import java.util.function.BiPredicate; import static io.netty.handler.codec.http2.Http2Error.PROTOCOL_ERROR; -import static io.netty.handler.codec.http2.Http2FrameCodecBuilder.forClient; import static io.servicetalk.http.netty.H2ServerParentChannelInitializer.initFrameLogger; final class H2ClientParentChannelInitializer implements ChannelInitializer { @@ -41,7 +40,7 @@ final class H2ClientParentChannelInitializer implements ChannelInitializer { @Override public void init(final Channel channel) { - final Http2FrameCodecBuilder multiplexCodecBuilder = forClient() + final Http2FrameCodecBuilder multiplexCodecBuilder = new OptimizedHttp2FrameCodecBuilder(false) // We do not want close to trigger graceful closure (go away), instead when user triggers a graceful // close, we do the appropriate go away handling. .decoupleCloseAndGoAway(true) diff --git a/servicetalk-http-netty/src/main/java/io/servicetalk/http/netty/H2ServerParentChannelInitializer.java b/servicetalk-http-netty/src/main/java/io/servicetalk/http/netty/H2ServerParentChannelInitializer.java index f98f33dccd..aba619e6c8 100644 --- a/servicetalk-http-netty/src/main/java/io/servicetalk/http/netty/H2ServerParentChannelInitializer.java +++ b/servicetalk-http-netty/src/main/java/io/servicetalk/http/netty/H2ServerParentChannelInitializer.java @@ -1,5 +1,5 @@ /* - * Copyright © 2019-2020 Apple Inc. and the ServiceTalk project authors + * Copyright © 2019-2021 Apple Inc. and the ServiceTalk project authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,6 @@ import java.util.function.BiPredicate; import javax.annotation.Nullable; -import static io.netty.handler.codec.http2.Http2FrameCodecBuilder.forServer; import static io.servicetalk.logging.slf4j.internal.Slf4jFixedLevelLoggers.newLogger; final class H2ServerParentChannelInitializer implements ChannelInitializer { @@ -42,7 +41,7 @@ final class H2ServerParentChannelInitializer implements ChannelInitializer { @Override public void init(final Channel channel) { - final Http2FrameCodecBuilder multiplexCodecBuilder = forServer() + final Http2FrameCodecBuilder multiplexCodecBuilder = new OptimizedHttp2FrameCodecBuilder(true) // We do not want close to trigger graceful closure (go away), instead when user triggers a graceful // close, we do the appropriate go away handling. .decoupleCloseAndGoAway(true) diff --git a/servicetalk-http-netty/src/main/java/io/servicetalk/http/netty/OptimizedHttp2FrameCodecBuilder.java b/servicetalk-http-netty/src/main/java/io/servicetalk/http/netty/OptimizedHttp2FrameCodecBuilder.java new file mode 100644 index 0000000000..7aa42cbc6f --- /dev/null +++ b/servicetalk-http-netty/src/main/java/io/servicetalk/http/netty/OptimizedHttp2FrameCodecBuilder.java @@ -0,0 +1,55 @@ +/* + * Copyright © 2021 Apple Inc. and the ServiceTalk project authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.servicetalk.http.netty; + +import io.netty.handler.codec.http2.DefaultHttp2Connection; +import io.netty.handler.codec.http2.DefaultHttp2RemoteFlowController; +import io.netty.handler.codec.http2.Http2FrameCodec; +import io.netty.handler.codec.http2.Http2FrameCodecBuilder; +import io.netty.handler.codec.http2.Http2RemoteFlowController; +import io.netty.handler.codec.http2.UniformStreamByteDistributor; + +/** + * Optimized variant of {@link Http2FrameCodecBuilder} that allows us to use {@link UniformStreamByteDistributor} + * for {@link Http2RemoteFlowController}. + */ +final class OptimizedHttp2FrameCodecBuilder extends Http2FrameCodecBuilder { + + private final boolean server; + + /** + * Creates a new instance. + * + * @param server {@code true} if for server, {@code false} otherwise + */ + OptimizedHttp2FrameCodecBuilder(final boolean server) { + this.server = server; + } + + @Override + public boolean isServer() { + return server; + } + + @Override + public Http2FrameCodec build() { + final DefaultHttp2Connection connection = new DefaultHttp2Connection(isServer(), maxReservedStreams()); + connection.remote().flowController(new DefaultHttp2RemoteFlowController(connection, + new UniformStreamByteDistributor(connection))); + connection(connection); + return super.build(); + } +} From e7215aa2487c30f6e955d587aebaee67371f52e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 May 2021 02:02:37 +0000 Subject: [PATCH 2/2] Bump gradle/wrapper-validation-action from 1 to 1.0.3 Bumps [gradle/wrapper-validation-action](https://github.com/gradle/wrapper-validation-action) from 1 to 1.0.3. - [Release notes](https://github.com/gradle/wrapper-validation-action/releases) - [Commits](https://github.com/gradle/wrapper-validation-action/compare/v1...v1.0.3) Signed-off-by: dependabot[bot] --- .github/workflows/gradle-wrapper-validation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index 0bde8aeca1..b27e310274 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -7,4 +7,4 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: gradle/wrapper-validation-action@v1 + - uses: gradle/wrapper-validation-action@v1.0.3