美文网首页springcloud
为Spring Cloud Ribbon/Zuul配置请求重试

为Spring Cloud Ribbon/Zuul配置请求重试

作者: 吴俊达 | 来源:发表于2017-05-07 14:15 被阅读5745次

    以下配置基于spring boot版本1.4.5.RELEASE,spring cloud版本采用Camden.SR6。

    工程环境如下:

    Paste_Image.png

    可以看到,compute-service服务包含了两个实例,实例1的端口号为2221、实例2的端口号2222。
    通过http://localhost:3333/add访问的时候,如果使用的是实例1,返回30;如果使用的是实例2,返回150;通过重复刷新http://localhost:3333/add,交替返回30和150,可以发现,此时通过ribbon,已经实现了客户端负载均衡。

    此时,关闭实例2,再次不断刷新http://localhost:3333/add,会交替返回30和“Whitelabel Error Page”的异常页面。可见,在访问到实例2的时候,直接返回了“Connection refused”的问题。

    为了解决这个问题,需要加入重试机制,在访问到实例2的时候, 遇到“Connection refused”,能够向实例1发起重试请求,从而返回正确结果。

    在ribbon工程的application.xml文件里面,加入如下配置:

    # 重试机制
    spring.cloud.loadbalancer.retry.enabled = true
    
    hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds = 10000
    
    compute-service.ribbon.ConnectTimeout = 250
    compute-service.ribbon.ReadTimeout = 1000
    
    # 对所有操作请求都进行重试
    compute-service.ribbon.OkToRetryOnAllOperations = true
    
    # 切换实例的重试次数
    compute-service.ribbon.MaxAutoRetriesNextServer = 2
    
    # 对当前实例的重试次数
    compute-service.ribbon.MaxAutoRetries = 1
    

    按照之前的步骤测试,仍然交替返回30和“Whitelabel Error Page”的异常页面,可见重试机制并未起效。

    此时,在pom文件加入spring-boot-starter-actuator模块

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    

    重启ribbon工程,观察http://localhost:3333/autoconfig,在negativeMatches下面,找到如下配置:

    Paste_Image.png

    可以看到,这里给出的提示是:RibbonAutoConfiguration.loadBalancedRetryPolicyFactory方法没有找到RetryTemplate的依赖。
    通过观察RibbonAutoConfiguration类的源码,可以看到如下代码:

    @Bean
    @ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
    public LoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory(SpringClientFactory clientFactory) {
        return new RibbonLoadBalancedRetryPolicyFactory(clientFactory);
    }
    

    可见,在存在RetryTemplate依赖的前提下,才能获得有效的ribbon负载均衡重试策略工厂。
    接下来,在pom文件,加入spring-retry的依赖:

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

    重启ribbon工程,重复刷新http://localhost:3333/add,在compute-service服务的实例1和实例2都正常的情况下,交替返回30和150;
    此时,关闭实例2,再次重复刷新http://localhost:3333/add,会发现,一直返回30。只是,有时候会有1秒左右的延时,可见此时是在向实例2请求的时候,发生了“Connection refused”,然后再向实例1重试发送请求。
    可见,重试机制已经生效。

    此时,再观察http://localhost:3333/autoconfig,在negativeMatches下面,会看到如下配置:

    Paste_Image.png

    通过观察RibbonAutoConfiguration类的源码,可以看到如下代码:

    @Bean
    @ConditionalOnMissingClass(value = "org.springframework.retry.support.RetryTemplate")
    public LoadBalancedRetryPolicyFactory neverRetryPolicyFactory() {
        return new LoadBalancedRetryPolicyFactory.NeverRetryFactory();
    }
    

    可见,要让重试机制不生效,需要去掉RetryTemplate的依赖。
    继续跟踪LoadBalancedRetryPolicyFactory的源码

    public interface LoadBalancedRetryPolicyFactory {
    
        public LoadBalancedRetryPolicy create(String serviceId, ServiceInstanceChooser serviceInstanceChooser);
    
        static class NeverRetryFactory implements LoadBalancedRetryPolicyFactory {
    
            @Override
            public LoadBalancedRetryPolicy create(String serviceId, ServiceInstanceChooser serviceInstanceChooser) {
                return null;
            }
        }
    }
    

    发现NeverRetryFactory的工厂方法直接返回了null,说明并未使用任何的重试策略机制。
    可见,在不引入spring-retry的情况下,是不会让重试策略生效的。

    为Zuul配置请求重试的方式,与Ribbon完全一致。

    相关文章

      网友评论

      • 丛大哈哈:到底是去掉 RetryTemplate的依赖 还是 加上RetryTemplate的依赖 啊
      • 大米饭320:感谢,非常有用
      • 王强儿:解决了我们的问题 搜索了很久才找到 多谢分享

      本文标题:为Spring Cloud Ribbon/Zuul配置请求重试

      本文链接:https://www.haomeiwen.com/subject/rhputxtx.html