SpringGateway使用loadbalance支持重试配置

这篇具有很好参考价值的文章主要介绍了SpringGateway使用loadbalance支持重试配置。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

使用webClient进行接口调用,在初始话webClient时添加 @Loadbalance注解

spring 自动装配置就会自动注入默认的filter

类:ReactorLoadBalancerClientAutoConfiguration

会自动注入 webClient 【RetryableLoadBalancerExchangeFilterFunction】 过滤器和重试策略【 RetryableExchangeFilterFunctionLoadBalancerRetryPolicy 重试策略】

    @ConditionalOnMissingBean
    @ConditionalOnProperty(value = "spring.cloud.loadbalancer.retry.enabled", havingValue = "true")
    @Bean
    public RetryableLoadBalancerExchangeFilterFunction retryableLoadBalancerExchangeFilterFunction(
            ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory,
            LoadBalancerRetryPolicy.Factory retryPolicyFactory,
            ObjectProvider<List<LoadBalancerClientRequestTransformer>> transformers) {
        return new RetryableLoadBalancerExchangeFilterFunction(retryPolicyFactory, loadBalancerFactory,
                transformers.getIfAvailable(Collections::emptyList));
    }

    @ConditionalOnMissingBean
    @ConditionalOnProperty(value = "spring.cloud.loadbalancer.retry.enabled", havingValue = "true")
    @Bean
    public LoadBalancerRetryPolicy.Factory loadBalancerRetryPolicy(
            ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory) {
        return new RetryableExchangeFilterFunctionLoadBalancerRetryPolicy.Factory(loadBalancerFactory);
    }

当发起http 请求时就会执行org.springframework.cloud.client.loadbalancer.reactive.RetryableLoadBalancerExchangeFilterFunction#filter 方法中

@Override
    public Mono<ClientResponse> filter(ClientRequest clientRequest, ExchangeFunction next) {
        URI originalUrl = clientRequest.url();
        String serviceId = originalUrl.getHost();
        if (serviceId == null) {
            String message = String.format("Request URI does not contain a valid hostname: %s", originalUrl.toString());
            if (LOG.isWarnEnabled()) {
                LOG.warn(message);
            }
            return Mono.just(ClientResponse.create(HttpStatus.BAD_REQUEST).body(message).build());
        }
        LoadBalancerRetryContext loadBalancerRetryContext = new LoadBalancerRetryContext(clientRequest);
        LoadBalancerProperties properties = loadBalancerFactory.getProperties(serviceId);

        Retry exchangeRetry = buildRetrySpec(properties.getRetry().getMaxRetriesOnSameServiceInstance(), true,
                properties.getRetry());
        Retry filterRetry = buildRetrySpec(properties.getRetry().getMaxRetriesOnNextServiceInstance(), false,
                properties.getRetry());
        LoadBalancerRetryPolicy retryPolicy = retryPolicyFactory.apply(serviceId);

        Set<LoadBalancerLifecycle> supportedLifecycleProcessors = LoadBalancerLifecycleValidator
                .getSupportedLifecycleProcessors(
                        loadBalancerFactory.getInstances(serviceId, LoadBalancerLifecycle.class),
                        RetryableRequestContext.class, ResponseData.class, ServiceInstance.class);
        String hint = getHint(serviceId, properties.getHint());
        RequestData requestData = new RequestData(clientRequest);
        DefaultRequest<RetryableRequestContext> lbRequest = new DefaultRequest<>(
                new RetryableRequestContext(null, requestData, hint));
        supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStart(lbRequest));

        //choose 默认使用轮询算法,选取一个节点
        return Mono.defer(() -> choose(serviceId, lbRequest).flatMap(lbResponse -> {
           //实例信息
            ServiceInstance instance = lbResponse.getServer();
            lbRequest.setContext(new RetryableRequestContext(instance, requestData, hint));
            if (instance == null) {
                String message = serviceInstanceUnavailableMessage(serviceId);
                if (LOG.isWarnEnabled()) {
                    LOG.warn(message);
                }
                supportedLifecycleProcessors.forEach(lifecycle -> lifecycle
                        .onComplete(new CompletionContext<ResponseData, ServiceInstance, RetryableRequestContext>(
                                CompletionContext.Status.DISCARD, lbRequest, lbResponse)));
                return Mono.just(ClientResponse.create(HttpStatus.SERVICE_UNAVAILABLE)
                        .body(serviceInstanceUnavailableMessage(serviceId)).build());
            }

            if (LOG.isDebugEnabled()) {
                LOG.debug(String.format("LoadBalancer has retrieved the instance for service %s: %s", serviceId,
                        instance.getUri()));
            }
            LoadBalancerProperties.StickySession stickySessionProperties = properties.getStickySession();
            ClientRequest newRequest = buildClientRequest(clientRequest, instance,
                    stickySessionProperties.getInstanceIdCookieName(),
                    stickySessionProperties.isAddServiceInstanceCookie(), transformers);
            supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStartRequest(lbRequest, lbResponse));
            return next.exchange(newRequest)
                    //请求执行失败
                    .doOnError(throwable -> supportedLifecycleProcessors.forEach(lifecycle -> lifecycle
                            .onComplete(new CompletionContext<ResponseData, ServiceInstance, RetryableRequestContext>(
                                    CompletionContext.Status.FAILED, throwable, lbRequest, lbResponse))))          //请求执行成功         
                     .doOnSuccess(clientResponse -> supportedLifecycleProcessors.forEach(
                            lifecycle -> lifecycle.onComplete(new CompletionContext<>(CompletionContext.Status.SUCCESS,
                                    lbRequest, lbResponse, new ResponseData(clientResponse, requestData)))))
                    .map(clientResponse -> {
                        loadBalancerRetryContext.setClientResponse(clientResponse);
                        //相同节点重试     
                        if (shouldRetrySameServiceInstance(retryPolicy, loadBalancerRetryContext)) {
                            if (LOG.isDebugEnabled()) {
                                LOG.debug(String.format("Retrying on status code: %d",
                                        clientResponse.statusCode().value()));
                            }
                            throw new RetryableStatusCodeException();
                        }
                        return clientResponse;

                    });
        }).map(clientResponse -> {
            loadBalancerRetryContext.setClientResponse(clientResponse);
             选取一个新的节点
            if (shouldRetryNextServiceInstance(retryPolicy, loadBalancerRetryContext)) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug(String.format("Retrying on status code: %d", clientResponse.statusCode().value()));
                }
                throw new RetryableStatusCodeException();
            }
            return clientResponse;

        }).retryWhen(exchangeRetry)).retryWhen(filterRetry);
    }

参数详细解:

retryableStatusCodes

默认情况下,Ribbon不会针对HTTP非正常响应状态值(如404、502等)进行重试。如果您需要对特殊的Http状态进行重试,需要配置该参数。

OkToRetryOnAllOperations

这个参数指的是是否允许所有的HTTP请求(GET,POST,PUT等)重试。默认值是false,只允许GET请求重试。对于POST等请求,请慎重使用。

MaxAutoRetries

这个参数用于配置当前实例最大重试次数,默认值为0。重试次数不包括第一次请求。

MaxAutoRetriesNextServer

这个参数指的是切换实例最大重试次数,默认值1。

如果访问当前实例异常,会再次尝试访问当前实例(次数由MaxAutoRetries决定);如果还不行,就会访问下一个实例;如果仍然不行,会把下一个实例作为当前实例并重试(次数由MaxAutoRetries决定)...依此类推,直到切换实例次数达到上限(由MaxAutoRetriesNextServer决定)。总共的重试次数计算公式:

- spring.cloud.loadbalancer.retry.enabled:启用或禁用重试。默认为 false。

- spring.cloud.loadbalancer.retry.repeat-services:是否在同一服务实例上重试。默认为 false。

- spring.cloud.loadbalancer.retry.retryable-status-codes:可重试的HTTP状态码。默认为 500,502,503。

- spring.cloud.loadbalancer.retry.backoff.first-backoff:第一次重试尝试之前等待的时间。默认为 1000ms。

- spring.cloud.loadbalancer.retry.backoff.max-backoff:重试之间等待的最长时间。默认为 2000ms。

- spring.cloud.loadbalancer.retry.backoff.multiplier:退避乘数。默认为 1.1。

重试方案2

添加依赖

<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.3.1</version>
</dependency>

添加配置

spring:
  cloud:
    gateway:
      routes:
        - id: my_route
          uri: http://example.com
          predicates:
            - Path=/my/path/**
          filters:
            - RewritePath=/my/path/(?<remaining>.*), /$\{remaining}
            - name: Retry
              args:
                retries: 3
                statuses: BAD_GATEWAY
                backoff:
                  firstBackoff: 1000ms
                  maxBackoff: 10000ms
                  factor: 2.0
          metadata:
            connectTimeout: 5000
            readTimeout: 10000

为my_route路由配置重试,最多重试3次,仅在收到BAD_GATEWAY响应时重试。配置了指数退避策略,第一次重试之前等待1秒,最多等待10秒,并且每次重试的等待时间是前一次的2倍。文章来源地址https://www.toymoban.com/news/detail-421739.html

到了这里,关于SpringGateway使用loadbalance支持重试配置的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 7.前置知识3:LoadBalance

    https://medium.com/google-cloud/understand-cloud-load-balancer-like-a-senior-engineer-d4f55f3111fc 负载均衡本来是个硬件设备。其实一开始确实是的,然而现在已经不同了。 尤其是云厂商提供的负载均衡方案几乎全部是靠软件。现在的负载均衡不仅是网络流量复杂均衡,几乎所有的平衡多个计算资

    2024年02月20日
    浏览(46)
  • 服务调用Ribbon,LoadBalance,Feign

    服务调用Ribbon、Fegin Ribbon实现负载均衡的原理 1:LoadBalancerAutoConfiguration这个类,这个类主要做的就是把LoadBalancer拦截器封装到RestTemplte拦截器集合里面去。 2:然后在代码里面调用restTemplate.getForObject或者其他方法的时候,就会调用到这个拦截器。 3:在LoadBalancer拦截器类中,

    2024年01月22日
    浏览(41)
  • 08 dubbo源码学习_LoadBalance

    它的职责是将网络请求,或者其他形式的负载“均摊”到不同的机器上。避免集群中部分服务器压力过大,而另一些服务器比较空闲的情况。通过负载均衡,可以让每台服务器获取到适合自己处理能力的负载 入口是在AbstractClusterInvoker中,这个抽象类要上一篇中已经讲过,它

    2023年04月26日
    浏览(32)
  • springgateway网关修改响应后,部分中文乱码问题

    是因为响应体过大,开启了压缩,数据分段进行响应得,导致处理返回体得时候乱码

    2024年02月11日
    浏览(32)
  • 自定义loadbalance实现feignclient的自定义路由

    服务A有多个同事同时开发,每个同事都在dev或者test环境发布自己的代码,注册到注册中心有好几个(本文nacos为例),这时候调用feign可能会导致请求到不同分支的服务上面,会出现一些问题,本文重点在于解决该问题 解决方案 调用流程 [外链图片转存失败,源站可能有防盗链机

    2024年02月11日
    浏览(38)
  • Vue3项目中没有配置 TypeScript 支持,使用 TypeScript 语法

    1.安装 TypeScript:首先,需要在项目中安装 TypeScript。在终端中运行以下命令 2.创建 TypeScript 文件:在 Vue 3 项目中,可以创建一个以 .ts 后缀的文件,例如 MyComponent.ts。在这个文件中,可以使用 TypeScript 语法编写代码。 在上面的示例中,我们使用 defineComponent 函数来定义一个

    2024年02月15日
    浏览(37)
  • 高效处理消息:使用Spring Boot实现消息重试机制

    当涉及到消息发送和接收的可靠性,Spring Boot提供了一些机制来确保消息的可靠传递。其中包括消息确认机制和重试机制。下面是一个示例代码,演示如何在Spring Boot中实现可靠的消息发送和接收。 首先,我们需要配置RabbitMQ的连接信息和相关属性。在 application.properties 文件中

    2024年02月11日
    浏览(47)
  • 使用 Spring Kafka 进行非阻塞重试的集成测试

    ​Kafka的非阻塞重试是通过为主题配置重试主题来实现的。如果需要,还可以配置额外的死信主题。如果所有重试都耗尽,事件将被转发到DLT。在公共领域中有很多资源可用于了解技术细节。对于代码中的重试机制编写集成测试确实是一项具有挑战性的工作。以下是一些测试

    2024年02月10日
    浏览(36)
  • 如果你需要使用重试机制,请使用Spring官方的Spring Retry

    Spring Retry 是 Spring Framework 中的一个模块,提供了一种简单的方式来在应用程序中实现重试机制。 在应用程序中,如果遇到了一些不可避免的错误,比如网络连接失败、数据库连接失败等,我们通常需要对这些错误进行重试,以尝试解决这些问题。 Spring Retry 提供了一个可插拔

    2024年02月13日
    浏览(38)
  • 【SpringBoot】springboot使用RestTemplate 进行http请求失败自动重试

    我们的服务需要调用别人的接口,由于对方的接口服务不是很稳定,经常超时,于是需要增加一套重试逻辑。这里使用 Spring Retry 的方式来实现。 一、引入POM 二、 修改启动类 在Spring Boot 应用入口启动类,也就是配置类的上面加上 @EnableRetry 注解,表示让重试机制生效。 注意

    2024年02月08日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包