Spring Cloud中的Feign和Ribbon通常都是协同工作,Feign和Ribbon中都存在重试机制,那么他们的重试机制是如何进行协同工作的呢?
feign的重试机制的实现类是Retryer,他的核心参数含义如下:
maxAttempts-最大尝试次数,默认值为5,首次请求也算一次,请求1次,重试4次。
period;-初始时间,用于参与计算线程休眠时间。
maxPeriod;-线程休眠的单次最大时间上限。
attempt;-尝试次数,每次尝试+1。
sleptForMillis;-线程累计休眠总时间。
Retryer定义
核心的重试代码如下:
- @Override
- public Object invoke(Object[] argv) throws Throwable {
- RequestTemplate template = buildTemplateFromArgs.create(argv);
- Options options = findOptions(argv);
- Retryer retryer = this.retryer.clone();
- while (true) {//这是一个循环操作
- try {
- return executeAndDecode(template, options); //执行请求 逻辑
- } catch (RetryableException e) {
- try {
- //连接超时或读取超时会进入到异常模块,则会执行Retryer逻辑
- retryer.continueOrPropagate(e); //执行Retryer逻辑
- } catch (RetryableException th) {
- //尝试重试次数用完,则会抛出异常
- Throwable cause = th.getCause();
- if (propagationPolicy == UNWRAP && cause != null) {
- throw cause; //结束循环逻辑
- } else {
- throw th; //结束循环逻辑
- }
- }
- if (logLevel != Logger.Level.NONE) {
- logger.logRetry(metadata.configKey(), logLevel); }
- continue; //继续下一次重试
- }
- }
- }
ribbon的重试机制是使用
RequestSpecificRetryHandler和LoadBalancerCommand来处理的,我们可以在配置文件定义参数,Spring框架会自动帮我们加载到RequestSpecificRetryHandler和LoadBalancerCommand的属性中去。核心参数如下。
- #读取超时,单位是毫秒
- ribbon.ReadTimeout=3000
- #连接超时,单位是毫秒
- ribbon.ConnectTimeout=3000
- #同一台实例最大重试次数
- ribbon.MaxAutoRetries=5
- #重试负载均衡其他的实例最大重试次数
- ribbon.MaxAutoRetriesNextServer=5
- #是否所有操作都重试,
- # false:get请求中,连接超时,读取超时都会重试,其他请求(put,post)连接超时重试,读取超时不重试。
- # true:get请求中,连接超时,读取超时都会重试,其他请求(put,post)连接超时重试,读取超时重试。
- ribbon.OkToRetryOnAllOperations=true
注意ReadTimeout和ConnectTimeout两个参数,它的值最开始是读取配置中的3秒和3秒,然后过程中又被重置为1秒和1秒,在最后要执行最终的查询的时候,又会从配置中获取然后覆盖为3秒和3秒。
重试的核心代码如下,执行完请求后,判断是否需要重试:
Feign和Ribbon的重试机制相当于一个双层循环,feign重试机制在外层,Ribbon的重试机制在里层,每执行一次feign的重试机制,内层的Ribbon的重试机制都会全部执行一次。