使用SpringBoot实现微服务超时重试模式 - Vinsguru


使用resilience4j的库和Spring Boot设计高弹性的微服务。
微服务本质上是分布式的。当您使用分布式系统时,请始终记住这一第一法则- 网络中可能发生任何事情。处理任何此类意外故障可能很难解决。故障可能是任何东西-应用程序,硬件或网络等。
系统从故障中恢复并保持正常运行的能力使系统更具 弹性。它还避免了下游服务的任何级联故障。
重试模式:
在微服务体系结构中,当有多个服务(A,B,C和D)时,一个服务(A)可能依赖于另一服务(B),而另一服务(B)又可能依赖于C,依此类推。有时由于某些问题,服务D可能无法按预期响应。服务D可能引发了某些异常,例如内存不足 错误或内部服务器错误。此类异常被级联到下游服务,这可能导致不良的用户体验,如下所示。

有时,当google.com对我们不起作用时,我们只是不放弃。我们假设页面下次可以正常工作,并且大多数情况下都会刷新页面,因此只需刷新页面即可。间歇性网络问题非常普遍。在微服务领域,我们可能正在运行同一服务D的多个实例,以实现高可用性和负载平衡。如果其中一个实例可能有问题,并且无法正确响应我们的请求,则如果我们重试该请求,则负载均衡器可以将请求发送到运行状况良好的节点并正确获得响应。因此,使用“重试”选项,我们有更多机会获得正确的响应。

 
让我们考虑这个简单的应用程序来解释此重试模式。

  • 如上所述,我们有多个微服务
  • 产品服务充当产品目录并负责提供产品信息
  • 产品服务取决于评级服务。
  • 评分服务维护产品评论和评分。 由于拥有大量数据而速度慢是众所周知的。
  • 每当我们查看产品详细信息时,产品服务就会将请求发送到评分服务,以获取该产品的评论。
  • 我们还有其他服务,例如帐户服务,订单服务和付款服务等,与本文的讨论无关。
  • 产品服务是一项核心服务,没有它,用户将无法启动订单工作流程。

 
设置:

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot2</artifactId>
    <version>1.6.1</version>
</dependency>

产品服务负责根据用户搜索条件提供产品列表。它是即使在关键负载下也应该启动和响应的核心服务之一。如果下降,将严重影响收入。由于此服务取决于评级服务,因此我们不希望任何网络问题或评级服务不可用性影响此产品服务。这就是使用 resilience4j 库的目的。

  • 我首先为resilience4j创建一个配置,  如下所示。在这里,我们将超时明确设置为3秒。我们可以在特定的超时时间内添加多个服务。
  • 我们可以有多种服务配置,如下所示。
  • 对于ratingService,我们将最多进行3次重试,延迟5秒。
  • retryExceptions:这些是我们将重试的异常。这是一个数组字段。您可以配置多个例外。
  • ignoreExceptions:有些异常我们可能不想重试。例如,一个错误的请求就是一个错误的请求。重试没有意义。因此,我们忽略了这一点。

resilience4j.retry:
  instances:
    ratingService:
      maxRetryAttempts: 3
      waitDuration: 5s
      retryExceptions:
        - org.springframework.web.client.HttpServerErrorException
      ignoreExceptions:
        - org.springframework.web.client.HttpClientErrorException
    someOtherService:
      maxRetryAttempts: 3
      waitDuration: 10s
      retryExceptions:
        - org.springframework.web.client.HttpServerErrorException
        - java.io.IOException


代码:

@Service
public class RatingServiceClient {

    private final RestTemplate restTemplate = new RestTemplate();

    @Value("${rating.service.endpoint}")
    private String ratingService;

    @Retry(name =
"ratingService", fallbackMethod = "getDefault")
    public CompletionStage<ProductRatingDto> getProductRatingDto(int productId){
        Supplier<ProductRatingDto> supplier = () ->
            this.restTemplate.getForEntity(this.ratingService + productId, ProductRatingDto.class)
                    .getBody();
        return CompletableFuture.supplyAsync(supplier);
    }

    private CompletionStage<ProductRatingDto> getDefault(int productId, HttpClientErrorException throwable){
        return CompletableFuture.supplyAsync(() -> ProductRatingDto.of(0, Collections.emptyList()));
    }

}

代码解释:

  • @Retry表示resilience4j将对该方法执行应用重试逻辑。
  • name = ratingService 表示 resilience4j 将使用yaml中的ratingService配置。
  •  当main方法由于某种原因失败时,将使用fallbackMethod。

 
总结
重试模式 是用于设计弹性微服务的最简单的微服务 设计模式之一。引入重试可以解决与网络相关的问题。
源代码可 在此处获得

超时模式源码可在此处获得