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
首先AbstractLoadBalancingClient的实现类有4个
先看下这些client开启的地方
org.springframework.cloud.netflix.ribbon.apache HttpClientRibbonConfiguration
在HttpClientRibbonConfiguration(按照spring的套路必有XXXConfiguration)
通过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里边有个地方需要注意
这里对Ribbon超时时间和hystrix的时间进行了一个校验,getribbontimeout 方法计算得出Ribbon超时时间 和当前的hystrix时间进行对比,hystrixTimeout小于ribbonTimeout,如果出现warn日志,这个就要注意了!
对于inithreadpool 这个方法大家要注意了,里边的hystrix参数很重要,这里就带过了!
结果快速的debug 终于到了关键的地方
这个地方是调用我们上面说的RibbonLoadBalancingHttpClient
这里边有两个关键的参数
OkToRetryOnAllOperations=false
如果这个参数开始,那么无论什么情况调用失败都会重试
okToRetryOnConnectErrors=false
这个是socket连接进行重试
这两个参数在RequestSpecificRetryHandler 类进行逻辑处理,这个方法是当我们zuul转发失败后触发的!
很显然我们配合的参数OkToRetryOnAllOperations是没用的,因为面试写死的false,okToRetryOnConnectErrors配置也是没用的,也是写死的false,那么只有一个条件可以触发,那就是ClientException ,这个异常类什么是否发生?大家可以自己看一下。
通过上面的分析发现RibbonLoadBalancingHttpClient触发retry的条件太苛刻了,只有发生ClientException的时候。
那么RetryableRibbonLoadBalancingHttpClient 如何呢?
我们引入了spring-retry包
略过一些繁琐的步骤,我们找到是否retry的地方
这里边有的变量retryable 他是什么了?进过参数的追踪的发现原来他是zuul.retryable变量默认是false,我们在配置文件设置成true
从代码中可以看出是用到了spring-retry 的 RetryTemplate进行retry!如果retryable设置成ture 才有后面的RetryPolicy策略
进入RetryPolicy我们看一下这个策略条件
RibbonLoadBalancedRetryPolicy 这个类
CanRetry 也就是get请求或者OkToRetryOnAllOperations=true的时候会发生retry
应为配置文件OkToRetryOnAllOperations=true ,所以只要失败就会try,这个做法时候合理吗?
我们先来开启OkHttpLoadBalancingClient
ribbon.okhttp.enabled=true
ribbon.httpclient.enabled=false
并没有重试机制
引入spring-retry包
开启RetryableOkHttpLoadBalancingClient 调用了retry策略
实现AbstractLoadBalancingClient的类有
开启条件
开启条件
开启条件
默认
开启条件
Retry 次数计算
reTry次数的计算= (MaxAutoRetries*+1)*(MaxAutoRetriesNextServer+1)
超时最大时间
ribbonTimeout=(ribbonReadTimeout+ ribbonConnectTimeout) * (maxAutoRetries + 1) * (maxAutoRetriesNextServer+ 1)
一、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
版权声明:本文为博主原创文章,转载请附上博文链接!