1、背景:
线上有一个接口是获取容器内监控CPU|GPU|内存等的指标值,因为接口响应速度慢,达到2S以上,所以需要进行优化。经过排查,发现这几个指标的值都是通过HTTP请求调取其它服务获取的,然后汇总返回,串行调用这几个接口,叠加时间就会使接口响应时间变长。
2、优化方式:
使用CompletableFuture
进行异步编排,对若干接口进行异步调用,然后等这些接口的结果全部返回后汇总进行最终结果返回。
3.实现:
3.1、创建一个大小合适的线程池:
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
4, 6, 3000L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(Integer.MAX_VALUE));
3.2、异步调用:
// 存放最终响应结果
ResourceMonitorData resourceMonitorData = new ResourceMonitorData();
// 异步获取GPU利用率,当异步调用完成时将结果设置到resourceMonitorData对象中
CompletableFuture<UsedRateData> gpuRateFuture = CompletableFuture.supplyAsync(() -> getGpuRate(url, param), executor)
.whenComplete((result, throwable) -> {
resourceMonitorData.setGpuRate(result);
if (throwable != null) {
log.error("[资源监控]获取GPU利用率失败,error: {}", throwable.getMessage());
}
});
CompletableFuture<UsedRateData> gpuMemoryRateFuture = CompletableFuture.supplyAsync(() -> getGpuMemoryRate(url, param), executor)
.whenComplete((result, throwable) -> {
resourceMonitorData.setGpuMemoryRate(result);
if (throwable != null) {
log.error("[资源监控]获取GPU显存利用率失败,error: {}", throwable.getMessage());
}
});
// 省略若干异步调用......
List<CompletableFuture<UsedRateData>> list = new ArrayList<>();
list.add(gpuRateFuture);
list.add(gpuMemoryRateFuture);
CompletableFuture<Void> all = CompletableFuture.allOf(list.toArray(new CompletableFuture[0]));
// 等待所有异步接口均返回结果
all.join();
return resourceMonitorData;
4、结果:
接口调用时间从2S降低至800ms左右,提升了接口响应速度。
5、总结:
使用异步方式优化接口响应速度时,会存在一个短板效应,也就是说最终能降低多少响应时长主要看这些异步调用中最慢的一个接口的响应时长,最终的响应时长一般都比这个最慢的接口再稍慢一点。