Spring 启动 Web 应用程序时多个 REST 调用超时
Multiple REST calls timing out in Spring Boot web application
我创建了一个 Spring Boot (1.4.2) REST 应用程序。 @RestController 方法之一需要调用第 3 方 API REST 操作 (RestOp1),其中 returns,比如 100-250 条记录。对于 RestOp1 返回的每条记录,在同一方法中,必须调用同一第 3 方 API (RestOp2) 的另一个 REST 操作。我的第一次尝试涉及使用基于大小为 100 的固定线程池的 Controller class 级别的 ExecutorService,以及返回与 RestOp2:
的响应相对应的记录的 Callable
// Executor thread pool - declared and initialized at class level
ExecutorService executor = Executors.newFixedThreadPool(100);
// Get records from RestOp1
ResponseEntity<RestOp1ResObj[]> restOp1ResObjList
= this.restTemplate.exchange(url1, HttpMethod.GET, httpEntity, RestOp1ResObj[].class);
RestOp1ResObj[] records = restOp1ResObjList.getBody();
// Instantiate a list of futures (to call RestOp2 for each record)
List<Future<RestOp2ResObj>> futureList = new ArrayList<>();
// Iterate through the array of records and call RestOp2 in a concurrent manner, using Callables.
for (int count=0; count<records.length; count++) {
Future<RestOp2ResObj> future = this.executorService.submit(new Callable<RestOp2ResObj>() {
@Override
public RestOp2ResObj call() throws Exception {
return this.restTemplate.exchange(url2, HttpMethod.GET, httpEntity, RestOp2Obj.class);
}
};
futureList.add(future);
});
// Iterate list of futures and fetch response from RestOp2 for each
// record. Build a final response and send back to the client.
for (int count=0; count<futureList.size(); count++) {
RestOp2ResObj response = futureList.get(count).get();
// use above response to build a final response for all the records.
}
至少可以说上面代码的性能很糟糕。 RestOp1 调用(仅调用一次)的响应时间约为 2.5 秒,而 RestOp2 调用(针对每条记录调用)的响应时间约为 1.5 秒。但是代码执行时间在 20-30 秒之间,而不是预期的 5-6 秒范围!我在这里遗漏了一些基本的东西吗?
您调用的服务是否足够快以每秒处理那么多请求?
有一个名为 AsyncRestService 的异步版本的 RestService 可用。你为什么不使用它?
我可能会这样:
AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate(new ConcurrentTaskExecutor(Executors.newFixedThreadPool(100)));
asyncRestTemplate.exchange("http://www.example.com/myurl", HttpMethod.GET, new HttpEntity<>("message"), String.class)
.addCallback(new ListenableFutureCallback<ResponseEntity<String>>() {
@Override
public void onSuccess(ResponseEntity<String> result) {
//TODO: Add real response handling
System.out.println(result);
}
@Override
public void onFailure(Throwable ex) {
//TODO: Add real logging solution
ex.printStackTrace();
}
});
您的问题涉及两部分:
- 多个 API 异步回调
- 处理超时(回退)
这两个部分是相关的,因为您必须处理每个调用的超时。
您可以考虑使用 Spring 云(基于 spring 引导)并使用一些基于 OSS Netflix 堆栈的开箱即用解决方案。
第一个(超时)on 应该是基于 feign client
的断路器hystrix
第二个(多个请求)这是一个架构问题,使用本机执行器不是一个好主意,因为它不会扩展并且维护成本很高。您可以继续 Spring Asynchrounous Methods 您将获得更好的结果并且完全 spring 合规。
希望这会有所帮助。
我创建了一个 Spring Boot (1.4.2) REST 应用程序。 @RestController 方法之一需要调用第 3 方 API REST 操作 (RestOp1),其中 returns,比如 100-250 条记录。对于 RestOp1 返回的每条记录,在同一方法中,必须调用同一第 3 方 API (RestOp2) 的另一个 REST 操作。我的第一次尝试涉及使用基于大小为 100 的固定线程池的 Controller class 级别的 ExecutorService,以及返回与 RestOp2:
的响应相对应的记录的 Callable// Executor thread pool - declared and initialized at class level
ExecutorService executor = Executors.newFixedThreadPool(100);
// Get records from RestOp1
ResponseEntity<RestOp1ResObj[]> restOp1ResObjList
= this.restTemplate.exchange(url1, HttpMethod.GET, httpEntity, RestOp1ResObj[].class);
RestOp1ResObj[] records = restOp1ResObjList.getBody();
// Instantiate a list of futures (to call RestOp2 for each record)
List<Future<RestOp2ResObj>> futureList = new ArrayList<>();
// Iterate through the array of records and call RestOp2 in a concurrent manner, using Callables.
for (int count=0; count<records.length; count++) {
Future<RestOp2ResObj> future = this.executorService.submit(new Callable<RestOp2ResObj>() {
@Override
public RestOp2ResObj call() throws Exception {
return this.restTemplate.exchange(url2, HttpMethod.GET, httpEntity, RestOp2Obj.class);
}
};
futureList.add(future);
});
// Iterate list of futures and fetch response from RestOp2 for each
// record. Build a final response and send back to the client.
for (int count=0; count<futureList.size(); count++) {
RestOp2ResObj response = futureList.get(count).get();
// use above response to build a final response for all the records.
}
至少可以说上面代码的性能很糟糕。 RestOp1 调用(仅调用一次)的响应时间约为 2.5 秒,而 RestOp2 调用(针对每条记录调用)的响应时间约为 1.5 秒。但是代码执行时间在 20-30 秒之间,而不是预期的 5-6 秒范围!我在这里遗漏了一些基本的东西吗?
您调用的服务是否足够快以每秒处理那么多请求?
有一个名为 AsyncRestService 的异步版本的 RestService 可用。你为什么不使用它?
我可能会这样:
AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate(new ConcurrentTaskExecutor(Executors.newFixedThreadPool(100)));
asyncRestTemplate.exchange("http://www.example.com/myurl", HttpMethod.GET, new HttpEntity<>("message"), String.class)
.addCallback(new ListenableFutureCallback<ResponseEntity<String>>() {
@Override
public void onSuccess(ResponseEntity<String> result) {
//TODO: Add real response handling
System.out.println(result);
}
@Override
public void onFailure(Throwable ex) {
//TODO: Add real logging solution
ex.printStackTrace();
}
});
您的问题涉及两部分:
- 多个 API 异步回调
- 处理超时(回退)
这两个部分是相关的,因为您必须处理每个调用的超时。
您可以考虑使用 Spring 云(基于 spring 引导)并使用一些基于 OSS Netflix 堆栈的开箱即用解决方案。
第一个(超时)on 应该是基于 feign client
的断路器hystrix第二个(多个请求)这是一个架构问题,使用本机执行器不是一个好主意,因为它不会扩展并且维护成本很高。您可以继续 Spring Asynchrounous Methods 您将获得更好的结果并且完全 spring 合规。
希望这会有所帮助。