2000qps的请求速率,直接将线程Blocked住,进程发生重启。
// 自定义线程池
val executor = Executors.newFixedThreadPool(32)
val dispatcher = Dispatcher(executor).apply {
maxRequests = 512
maxRequestsPerHost = 50
}
// 构建OkHttpClient
val client = OkHttpClient.Builder()
.dispatcher(dispatcher)
.connectTimeout(30, TimeUnit.SECONDS)
.build()
设置线程池和Dispatcher之后,重启减少,但是cpu使用率非常高。
通过arthas的thread -b发现:卡在enqueue之后
查看源码,发现是同步锁:
通过设置自定义线程池,去除enqueue调用,自定义异步之后,问题解决。
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.Executor;
public class AsyncHttpCall {
private final OkHttpClient client;
private final Executor executor; // 可选:自定义线程池
public AsyncHttpCall(OkHttpClient client, Executor executor) {
this.client = client;
this.executor = executor;
}
public CompletableFuture<Response> executeAsync(Request request) {
// 使用指定线程池或默认的 ForkJoinPool
return CompletableFuture.supplyAsync(() -> {
try (Response response = client.newCall(request).execute()) {
// 注意:确保在异步处理中正确关闭Response
return response.peekBody(Long.MAX_VALUE); // 避免直接关闭响应体
} catch (IOException e) {
throw new CompletionException("HTTP请求失败", e);
}
}, executor);
}
}
总结:高性能别用okhttpclient的enqueue方法进行异步。
是不是我用错了?大家有好的用法可以提出来。