我在Spring Boot中有一项新服务。为了满足一个请求,服务必须在执行器服务到位的情况下从多个来源收集数据。如何在此服务和下游服务之间使用Hystrix。
的链接让我们说我有一个SERVICE A,它需要两次调用SERVICE B,并且需要SERVICE B的结果调用200次SERVICE C,然后它才能响应。我有一个执行服务,可以并行调用服务。
我已经尝试使用SEMAPHORE Configuration的@HystrixCommand来处理SERVICE A,SERVICE B和SERVICE C之间的所有服务调用。
当我为服务C安排线程时,Hystrix开始启动,并且从服务A到服务C的200个调用中的一些被触发。
SERVICE A期望的响应时间:1秒 服务B的响应时间:300 ms SERVICE C的响应时间:40-100毫秒
使用的AWS Beanstalk机器具有8核心CPU。
我还使用redis缓存来缓存SERVICE C的响应。但是无法缓存SERVICE B调用,它具有动态结果。
执行器服务配置:
@Bean
public Executor asyncGCPExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(30);
executor.setMaxPoolSize(50);
executor.setThreadNamePrefix("async-");
executor.setKeepAliveSeconds(10);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.initialize();
return executor;
}
Hystrix配置:
hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests=100
hystrix.command.default.execution.isolation.strategy=SEMAPHORE
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=600
尝试了许多不同数量的线程配置和超时,但这没有帮助。 请以正确的hystrix配置指导我。
如果情况不清楚,请告诉我。
某些代码:
@RestController
@Slf4j
class CollectorController {
private final CollectorService collectorService;
public CollectorController(final CollectorService collectorService) {
this.collectorService = collectorService;
}
@GetMapping(value = "/collections")
public ResponseEntity<List<String>> getResponseForCollection(@ModelAttribute final Request request) {
final List<String> response;
try {
response = this.collectorService.getCollections(request);
} catch (final ExecutionException e) {
return ResponseEntity.badRequest().build();
} catch (final InterruptedException e) {
return ResponseEntity.badRequest().build();
}
return ResponseEntity.ok(response);
}
}
@Data
class Request {
private String username;
private String cid;
}
@Service
class CollectorService {
private final ServiceA serviceA;
private final ServiceB serviceB;
private final ArrangementService arrangementService;
CollectorService(final ServiceA serviceA, final ServiceB serviceB,
final ArrangementService arrangementService) {
this.serviceA = serviceA;
this.serviceB = serviceB;
this.arrangementService = arrangementService;
}
public List<String> getCollections(final Request request) throws ExecutionException, InterruptedException {
final CompletableFuture<List<String>> collectionByUsernameAndCid = serviceA.getCollectionByUsernameAndCid(request);
final List<CompletableFuture<String>> completableFutures = new ArrayList<>();
collectionByUsernameAndCid.get().forEach(source -> {
final CompletableFuture<String> detailsBySource = serviceB.getDetailsBySource(source);
completableFutures.add(detailsBySource);
});
final int size = completableFutures.size();
CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[size])).join();
return arrangementService.arrangeAll(completableFutures);
}
}
@Service
class ArrangementService {
public List<String> arrangeAll(final List<CompletableFuture<String>> completableFutureList) {
return completableFutureList.stream().map(completableFuture -> {
try {
return completableFuture.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return null;
})
.collect(Collectors.toList());
}
}
@Service
class ServiceA {
private final ServiceACollector serviceACollector;
ServiceA(final ServiceACollector serviceACollector) {
this.serviceACollector = serviceACollector;
}
@Async
public CompletableFuture<List<String>> getCollectionByUsernameAndCid(final Request request) {
final List<String> responseFromServiceA = serviceACollector.getResponseFromServiceA(request.getUsername(), request.getCid());
if (null == responseFromServiceA || responseFromServiceA.isEmpty()) {
return CompletableFuture.completedFuture(Collections.EMPTY_LIST);
}
return CompletableFuture.completedFuture(responseFromServiceA);
}
}
@Service
class ServiceB {
private final ServiceBCollector serviceBCollector;
ServiceB(final ServiceBCollector serviceBCollector) {
this.serviceBCollector = serviceBCollector;
}
@Async
public CompletableFuture<String> getDetailsBySource(final String source) {
final String responseFromServiceB = serviceBCollector.getResponseFromServiceB(source);
if (null == responseFromServiceB || responseFromServiceB.isEmpty()) {
return CompletableFuture.completedFuture(null);
}
return CompletableFuture.completedFuture(responseFromServiceB);
}
}
@Service
class ServiceACollector {
private final RestTemplate restTemplate;
ServiceACollector(final RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
/**
* The CacheManager does not allow null values.
* So if hystrix fallback method returns null then its not cached.
*
* @param username
* @param cid
* @return 200 list of String
*/
@Cacheable(key = "{#username, #cid}", cacheManager = "oneHourCacheManager", value = "ServiceACollector")
@HystrixCommand(fallbackMethod = "defaultResponseFromServiceA")
public List<String> getResponseFromServiceA(final String username, final String cid) {
final ResponseEntity<List<String>> responseEntity = this.restTemplate.exchange(
"http://my-rest-url.org/rest/account/{username}/{cid}", HttpMethod.GET,
null, new ParameterizedTypeReference<List<String>>() {
}, username, cid);
return responseEntity.getBody();
}
public List<String> defaultResponseFromServiceA(final String username, final String cid) {
return null;
}
}
@Service
class ServiceBCollector {
public final RestTemplate restTemplate;
ServiceBCollector(final RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
/**
* The CacheManager does not allow null values.
* So if hystrix fallback method returns null then its not cached.
*
*
* @param source
* @return
*/
@Cacheable(key = "{#source}", cacheManager = "oneHourCacheManager", value = "ServiceBCollector")
@HystrixCommand(fallbackMethod = "defaultResponseFromServiceB")
public String getResponseFromServiceB(final String source) {
final ResponseEntity<String> responseEntity = this.restTemplate.exchange(
"http://my-rest-url.org/rest/details/{source}", HttpMethod.GET,
null, String.class, source);
return responseEntity.getBody();
}
public String defaultResponseFromServiceB(final String username, final String cid) {
return null;
}
}