OkHttp h2c协议性能低于HTTP/1.1,并发越高表现越差求排查
微服务通信升级HTTP/2的h2c性能异常排查
我正在调研微服务间通信是否升级HTTP/2,使用OkHttp测试h2c协议性能,结果不符合预期:h2c性能不如HTTP/1.1,且并发线程越多表现越差。测试采用JMH工具,服务端为启用HTTP/2的Spring Web服务器,原本预期h2c能带来更高性能。
测试数据
# 20 thread http1.1 Benchmark Mode Cnt Score Error Units JMHTest.request avgt 10 30.997 ± 0.185 ms/op h2c Benchmark Mode Cnt Score Error Units JMHTest.request avgt 10 32.816 ± 1.022 ms/op # 50 thread http1.1 Benchmark Mode Cnt Score Error Units JMHTest.request avgt 10 31.286 ± 0.555 ms/op h2c Benchmark Mode Cnt Score Error Units JMHTest.request avgt 10 72.564 ± 0.678 ms/op
测试环境
- Jdk:
openjdk version "17.0.6" 2023-01-17 LTS - okhttp3:
5.0.0-alpha.12
客户端代码
JMH测试类
@State(Scope.Benchmark) public class JMHTest { private static final OkHttpClient CLIENT = HttpClientFactory.buildH2PriorClient(); private static final String URL = "http://localhost:8080/hello"; private static final Request REQUEST = new Request.Builder() .url(URL) .post(RequestBody.create(MediaType.get("text/plain"), BodyConstant.BODY_100B)) .build(); public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder() .include(JMHTest.class.getSimpleName()) .build(); new Runner(opt).run(); } @BenchmarkMode({Mode.AverageTime}) @OutputTimeUnit(TimeUnit.MILLISECONDS) @Fork(value = 2, warmups = 1) @Warmup(iterations = 2) @Measurement(iterations = 5) @Threads(20) @Benchmark public void request() { post(); } @SneakyThrows private void post() { Call call = CLIENT.newCall(REQUEST); try (Response response = call.execute()) { try (ResponseBody body = response.body()) { if (!response.isSuccessful()) { throw new RuntimeException(); } } } } }
HttpClient工厂类
public class HttpClientFactory { public static OkHttpClient buildClient() { return getClientBuilder().build(); } public static OkHttpClient buildH2PriorClient() { OkHttpClient.Builder builder = getClientBuilder(); builder.setProtocols$okhttp(List.of(Protocol.H2_PRIOR_KNOWLEDGE)); return builder.build(); } @SneakyThrows private static OkHttpClient.Builder getClientBuilder() { OkHttpClient.Builder builder = new OkHttpClient.Builder(); builder.setReadTimeout$okhttp(3000); builder.setConnectTimeout$okhttp(3000); builder.setReadTimeout$okhttp(3000); builder.setWriteTimeout$okhttp(3000); return builder; } }
可能的问题排查方向
- OkHttp版本缺陷:使用的
5.0.0-alpha.12是Alpha测试版本,HTTP/2实现可能存在未优化的性能瓶颈,建议切换到4.x系列的稳定版本重新测试。 - 连接池配置不足:HTTP/2依赖单连接多路复用,但你未自定义连接池配置,默认连接池的大小可能无法支撑高并发场景,导致线程阻塞等待连接。可尝试调整连接池参数:
builder.connectionPool(new ConnectionPool(10, 5, TimeUnit.MINUTES)); - 测试场景不匹配:当前用100B的极小请求体,HTTP/1.1的头部开销影响有限,而HTTP/2的多路复用优势在小请求高并发场景下需要合理的连接配置才能体现。可尝试增大请求体大小,或增加请求频次模拟真实微服务通信。
- JMH测试配置问题:测试50线程时是否修改了
@Threads注解?需确保预热和测量阶段足够充分,可增加@Fork次数减少测试误差,比如设置@Fork(3)。 - 服务端配置瓶颈:检查Spring Web服务器的HTTP/2配置,是否限制了单连接的最大流数量,或服务端线程池配置未适配HTTP/2特性,导致高并发下处理能力不足。
请问是我的测试方法或场景存在问题吗?
内容的提问来源于stack exchange,提问作者Eda
相关产品推荐
相关产品推荐

