Hystrix在春季启动中带有ExecutorService

时间:2019-08-02 17:32:12

标签: spring-boot executorservice hystrix

我在Spring Boot中有一项新服务。为了满足一个请求,服务必须在执行器服务到位的情况下从多个来源收集数据。如何在此服务和下游服务之间使用Hystrix。

service image

的链接

让我们说我有一个SERVICE A,它需要两次调用SERVICE B,并且需要SERVICE B的结果调用200次SERVICE C,然后它才能响应。我有一个执行服务,可以并行调用服务。

我已经尝试使用SEMAPHORE Con​​figuration的@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;
}
}

0 个答案:

没有答案