利用JMH基准测试对比不同HTTP客户端(OkHttp vs HttpClient)调用美团API性能

在对接美团开放平台等第三方服务时,HTTP 客户端的选型直接影响系统吞吐量与响应延迟。常见的 Java HTTP 客户端包括 Apache HttpClient 与 OkHttp。为科学评估二者在真实场景下的性能差异,本文使用 JMH(Java Microbenchmark Harness) 编写基准测试,模拟高并发下对美团 API 的调用,并给出可复现的代码与结果分析。

引入依赖

首先,在 Maven 项目中添加 JMH、OkHttp 与 Apache HttpClient 依赖:

<dependencies>
    <dependency>
        <groupId>org.openjdk.jmh</groupId>
        <artifactId>jmh-core</artifactId>
        <version>1.37</version>
    </dependency>
    <dependency>
        <groupId>org.openjdk.jmh</groupId>
        <artifactId>jmh-generator-annprocess</artifactId>
        <version>1.37</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.squareup.okhttp3</groupId>
        <artifactId>okhttp</artifactId>
        <version>4.12.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents.client5</groupId>
        <artifactId>httpclient5</artifactId>
        <version>5.2.1</version>
    </dependency>
</dependencies>

封装两种客户端的美团 API 调用工具类

为保证测试公平性,统一请求 URL、超时时间与重试策略。

package baodanbao.com.cn.meituan.client;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.io.entity.EntityUtils;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

public class MeituanApiClient {

    private static final String MOCK_API_URL = "https://mock.baodanbao.com.cn/meituan/order/status?orderId=ORD20260113";

    // OkHttp 客户端(复用)
    private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient.Builder()
        .connectTimeout(2, TimeUnit.SECONDS)
        .readTimeout(3, TimeUnit.SECONDS)
        .writeTimeout(3, TimeUnit.SECONDS)
        .build();

    // Apache HttpClient(复用)
    private static final CloseableHttpClient HTTP_CLIENT = HttpClients.custom()
        .setConnectionTimeToLive(30, TimeUnit.SECONDS)
        .disableAutomaticRetries()
        .build();

    public static String callWithOkHttp() throws IOException {
        Request request = new Request.Builder().url(MOCK_API_URL).build();
        try (Response response = OK_HTTP_CLIENT.newCall(request).execute()) {
            return response.body() != null ? response.body().string() : "";
        }
    }

    public static String callWithApacheHttpClient() throws IOException {
        HttpGet httpGet = new HttpGet(MOCK_API_URL);
        httpGet.setConfig(org.apache.hc.client5.http.config.RequestConfig.custom()
            .setConnectTimeout(org.apache.hc.core5.util.Timeout.ofSeconds(2))
            .setResponseTimeout(org.apache.hc.core5.util.Timeout.ofSeconds(3))
            .build());
        try (var response = HTTP_CLIENT.execute(httpGet)) {
            return EntityUtils.toString(response.getEntity());
        }
    }
}

注:实际测试中应使用真实美团沙箱环境或本地 Mock Server,确保网络延迟可控。

编写 JMH 基准测试类

使用 @BenchmarkMode@Fork@Threads 等注解控制测试行为:

package baodanbao.com.cn.meituan.benchmark;

import baodanbao.com.cn.meituan.client.MeituanApiClient;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
@Fork(value = 2, jvmArgs = {"-Xms2g", "-Xmx2g"})
@Threads(16)
@Warmup(iterations = 3, time = 5)
@Measurement(iterations = 5, time = 10)
public class HttpClientsBenchmark {

    @Benchmark
    public void testOkHttp(Blackhole blackhole) throws IOException {
        String result = MeituanApiClient.callWithOkHttp();
        blackhole.consume(result);
    }

    @Benchmark
    public void testApacheHttpClient(Blackhole blackhole) throws IOException {
        String result = MeituanApiClient.callWithApacheHttpClient();
        blackhole.consume(result);
    }

    public static void main(String[] args) throws RunnerException {
        Options options = new OptionsBuilder()
            .include(HttpClientsBenchmark.class.getSimpleName())
            .build();
        new Runner(options).run();
    }
}

关键配置说明

  • @Fork(2):启动两个独立 JVM 进程,避免 JIT 优化干扰。
  • @Threads(16):模拟 16 个并发线程调用,贴近真实高并发场景。
  • @Warmup@Measurement:预热 3 轮,正式测量 5 轮,每轮持续指定秒数。
  • Blackhole:防止 JVM 优化掉无副作用的返回值。

典型测试结果(示例)

在 8 核 16G Linux 服务器上运行后,可能得到如下输出(单位:毫秒/操作):

Benchmark                              Mode  Cnt   Score   Error  Units
HttpClientsBenchmark.testOkHttp        avgt   10   42.35 ± 1.21  ms/op
HttpClientsBenchmark.testApacheHttpClient avgt   10   48.76 ± 1.89  ms/op

结果显示,在相同条件下,OkHttp 平均响应时间比 Apache HttpClient 快约 13%。这主要得益于 OkHttp 内置连接池、高效的 I/O 处理及更轻量的内部结构。

注意事项

  • 所有客户端实例必须复用,避免每次创建新连接导致结果失真。
  • 测试应避开网络抖动高峰,建议在内网 Mock Server 上进行。
  • 若需测试 HTTPS 性能,应启用 TLS 会话复用并配置相同的安全协议版本。
  • JMH 默认不捕获异常,若 API 返回 4xx/5xx,需在工具类中处理以避免测试中断。

通过 JMH 可量化评估不同 HTTP 客户端在特定业务场景下的性能表现,为技术选型提供数据支撑。

本文著作权归 俱美开放平台 ,转载请注明出处!

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐