Zuul ribbon 重试失效分析

Zuul ribbon 重试机制

问题描述:

Zuul转发POST请求接口异常,read timeout,没有进行重试,期望进行重试!

配置参数模拟

 spring.cloud.loadbalancer.retry.enabled=true

ribbon.ConnectTimeout=5000

ribbon.ReadTimeout=5000

ribbon.OkToRetryOnAllOperations=true

ribbon.MaxAutoRetries=1

ribbon.MaxAutoRetriesNextServer=0

问题分析

  1. post请求read timeout 是否需要进行重试
  2. ribbon重试的条件是什么
  3. 为什么参数没有没有达到预期的重试效果

 

首先AbstractLoadBalancingClient的实现类有4个

 

先看下这些client开启的地方

org.springframework.cloud.netflix.ribbon.apache HttpClientRibbonConfiguration

在HttpClientRibbonConfiguration(按照spring的套路必有XXXConfiguration)

通过HttpClientRibbonConfiguration我们发现下面的代码:

Zuul ribbon 重试失效分析_第1张图片 

HttpClientRibbonConfiguration开启了两个类

1.RibbonLoadBalancingHttpClient

2.RetryableRibbonLoadBalancingHttpClient(spring-try)

根据org.springframework.retry.support.RetryTemplate 类是否存在,来决定加载哪个ribbonbalance,这个类属于spring-retry包,

从工程中找了一下类,显然没有这个类。显然的是
RibbonLoadBalancingHttpClient ,我们来分析一下这个类是怎么被调用的

因为zuul 引入了ribbion和hystrix 所以我们从org.springframework.cloud.netflix.zuul.filters.route.support. AbstractRibbonCommand 进行入手,因为他继承了HystrixCommand,他的run方法里边必然是调用RibbonLoadBalancingHttpClient入口!

AbstractRibbonCommand里边有个地方需要注意

Zuul ribbon 重试失效分析_第2张图片 

这里对Ribbon超时时间和hystrix的时间进行了一个校验,getribbontimeout 方法计算得出Ribbon超时时间 和当前的hystrix时间进行对比,hystrixTimeout小于ribbonTimeout,如果出现warn日志,这个就要注意了!

Zuul ribbon 重试失效分析_第3张图片 

对于inithreadpool 这个方法大家要注意了,里边的hystrix参数很重要,这里就带过了!

结果快速的debug 终于到了关键的地方

Zuul ribbon 重试失效分析_第4张图片 

这个地方是调用我们上面说的RibbonLoadBalancingHttpClient

这里边有两个关键的参数

OkToRetryOnAllOperations=false

如果这个参数开始,那么无论什么情况调用失败都会重试

okToRetryOnConnectErrors=false

这个是socket连接进行重试

这两个参数在RequestSpecificRetryHandler 类进行逻辑处理,这个方法是当我们zuul转发失败后触发的!

Zuul ribbon 重试失效分析_第5张图片 

很显然我们配合的参数OkToRetryOnAllOperations是没用的,因为面试写死的false,okToRetryOnConnectErrors配置也是没用的,也是写死的false,那么只有一个条件可以触发,那就是ClientException ,这个异常类什么是否发生?大家可以自己看一下。

通过上面的分析发现RibbonLoadBalancingHttpClient触发retry的条件太苛刻了,只有发生ClientException的时候。

那么RetryableRibbonLoadBalancingHttpClient 如何呢?

我们引入了spring-retry包

略过一些繁琐的步骤,我们找到是否retry的地方

Zuul ribbon 重试失效分析_第6张图片 

 

这里边有的变量retryable 他是什么了?进过参数的追踪的发现原来他是zuul.retryable变量默认是false,我们在配置文件设置成true

从代码中可以看出是用到了spring-retry 的 RetryTemplate进行retry!如果retryable设置成ture 才有后面的RetryPolicy策略

进入RetryPolicy我们看一下这个策略条件

RibbonLoadBalancedRetryPolicy 这个类

 

CanRetry 也就是get请求或者OkToRetryOnAllOperations=true的时候会发生retry

应为配置文件OkToRetryOnAllOperations=true ,所以只要失败就会try,这个做法时候合理吗?

OkHttpRibbonConfiguration开启了两个类

  1. RetryableOkHttpLoadBalancingClient(spring-retry)
  2. OkHttpLoadBalancingClient

我们先来开启OkHttpLoadBalancingClient

ribbon.okhttp.enabled=true

ribbon.httpclient.enabled=false

Zuul ribbon 重试失效分析_第7张图片 

并没有重试机制

引入spring-retry

Zuul ribbon 重试失效分析_第8张图片

开启RetryableOkHttpLoadBalancingClient 调用了retry策略

总结:

实现AbstractLoadBalancingClient的类有

  1.RetryableOkHttpLoadBalancingClient(spring-retry)

     开启条件

  1. ribbon.okhttp.enabled=true
  2. ribbon.httpclient.enabled=false
  3. 导入spring-retry

  2.OkHttpLoadBalancingClient

     开启条件

  1. ribbon.okhttp.enabled=true
  2. ribbon.httpclient.enabled=false

  3.RibbonLoadBalancingHttpClient

      开启条件

       默认

  4.RetryableRibbonLoadBalancingHttpClient(spring-try)

    开启条件

  1. spring.cloud.loadbalancer.retry.enabled=true
  2. zuul.retryable=true
  3. 导入spring-try

Retry 次数计算

 Zuul ribbon 重试失效分析_第9张图片

reTry次数的计算= (MaxAutoRetries*+1)*(MaxAutoRetriesNextServer+1)

超时最大时间

ribbonTimeout=(ribbonReadTimeout+ ribbonConnectTimeout) * (maxAutoRetries + 1) * (maxAutoRetriesNextServer+ 1)

引用CSDN HTTPCLIENT和OKHTTP对比

一、HttpClient:

HttpClient 是Apache的一个三方网络框架,网络请求做了完善的封装,api众多,用起来比较方便,开发快。实现比较稳定,bug比较少,但是正式由于其api众多,是我们很难再不破坏兼容性的情况下对其进行扩展。所以,Android团队对提升和优化httpclient积极性并不高。android5.0被废弃,6.0逐渐删除。

二、HttpURLConnection

HttpURLConnection是一个多用途、轻量级的http客户端。它对网络请求的封装没有HttpClient彻底,api比较简单,用起来没有那么方便。但是正是由于此,使得我们能更容易的扩展和优化的HttpURLConnection。不过,再android2.2之前一直存在着一些令人烦的bug,比如一个人可读的inputstream调用它的close方法的时候,会使得连接池实效,通常的做法就是禁用连接池。因此,在android2.2之前建议使用稳定的HttpClient,android2.2之后使用更容易扩展和优化的HttpURLConnection。

三、okhttp

支持Android 2.3及其以上版本;

支持Java JDK 1.7以上版本;

okhttp是专注于提升网络连接效率的http客户端。

1、它能实现同一ip和端口的请求重用一个socket,这种方式能大大降低网络连接的时间,和每次请求都建立socket,再断开socket的方式相比,降低了服务器服务器的压力。

2、okhttp 对http和https都有良好的支持。

3、okhttp 不用担心android版本变换的困扰。

4、成熟的网络请求解决方案,比HttpURLConnection更好用。

4、缺点,okhttp请求网络切换回来是在线程里面的,不是在主线程,不能直接刷新UI,需要我们手动处理。封装比较麻烦。

 

四、Volley

Volley是google在2013 io大会上推出的网络通信框架,特别适合处理数据量小,通信频繁的网络操作。优点是内部封装了异步线程,可直接在主线程请求网络,并处理返回的结果。同时可以取消请求,容易扩展。缺点是:面对大数据量的请求,比如下载表现糟糕,不支持https。Volley的底层在针对android2.3以下系统使用httpclicent,在android2.3以上采用HttpUrlConnection请求网络。

本公司的选择:

公司使用Volley框架来处理网络请求,但是,当数据量需求越来大的时候,Volley在面对大数据量的网络请求的表现并不好,加上公司大量采用https协议。于是,公司网络请求采用了Volley+okhttp。正如我们采用这种方式的优势有:

1、okhttp 不用担心android版本变换的困扰。

2、okhttp 对大数据量的网络请求支持非常好。

3、okhttp 同时支持http和https

4、okhttp 重用socket连接,网络请求效率非常高。

5、Volley框架在异步请求的封装非常好,对子线程网络请求,主线程更新UI支持非常好。能像Image-Loader一样轻松加载网络图片。

总之,网络请求底层采用okhttp,异步回调使用Volley框架。

后续还有对xutils 和 Retrofit2的分析。

作者:heqinglin8

来源:CSDN

原文:https://blog.csdn.net/langtop/article/details/77972855

版权声明:本文为博主原创文章,转载请附上博文链接!

你可能感兴趣的:(Zuul ribbon 重试失效分析)