一次线上超时问题,看Ribbon 超时机制

一、线上问题

项目上线后,一段时间内运行都没有问题,突然运营人员说,某个接口一直失败。遂查看线上日志:

一次线上超时问题,看Ribbon 超时机制_第1张图片

spring-cloud-openfeign 通过服务名调用的,服务发现没有找到可用服务实例?这是第一反应,应为没有看到目标 IP ,这个想法通过另外一个ping 接口调用被推翻了,于是怀疑是超时参数设置问题。

默认参数一定是有的,而且我的 OkhttpClient 对象已经设置了超时:

@Configuration
@ConditionalOnClass({Feign.class})
@AutoConfigureBefore({FeignAutoConfiguration.class})
public class OKHttpConfig {
    @Value("${feign.okhttp.maxidleConnections}")
    private Integer maxidleConnections;
    @Value("${feign.okhttp.keepAliveDuration}")
    private Integer keepAliveDuration;

    public OKHttpConfig() {
    }

    @Bean
    @LoadBalanced
    public OkHttpClient okHttpClient() {
        return (new OkHttpClient()).newBuilder().retryOnConnectionFailure(true).connectionPool(this.pool()).connectTimeout(100000L, TimeUnit.SECONDS).readTimeout(100000L, TimeUnit.SECONDS).writeTimeout(100000L, TimeUnit.SECONDS).build();
    }

    @Bean
    public ConnectionPool pool() {
        return new ConnectionPool(this.maxidleConnections, (long)this.keepAliveDuration, TimeUnit.MINUTES);
    }
}

按照推测,明显这个没起作用,所以只能去看下具体调用时超时参数到底是怎么起作用的:

二、源码剖析

Ribbon 作为负载均衡调用 openFeign。会涉及到两个超时,一个是 Ribbon 的超时设置,一个是 openFeign 底层使用的 delegate 的超时。比如 httClient 或者 OkhttpClient。

下面看下这两个超时参数的设置方法:

# 注意这里对应的 org.springframework.cloud.openfeign.FeignClientProperties,并不是直接给 okhttp 使用的,会覆盖 okhttpClient 对象构造时设置的超时参数!
feign:
  client:
    config:
      default:
        connect-timeout: 20000
        read-timeout: 20000
  httpclient:
    enabled: false
  okhttp:
    enabled: true
    maxidleConnections: 150
    keepAliveDuration: 10

ribbon:
  ConnectTimeout: 5000
  ReadTimeout: 10000    

这两个参数同时设置或者只设置一个时到底会怎么作用呢,通过源码我们去了解下:

一次线上超时问题,看Ribbon 超时机制_第2张图片

一次线上超时问题,看Ribbon 超时机制_第3张图片

一次线上超时问题,看Ribbon 超时机制_第4张图片

通过上面的代码可以看出,如果没有显式配置 configOverride,会使用 默认的 1s ,所以线上随着数据量的增加,接口一旦返回慢一点就会报超时错误!!

一次线上超时问题,看Ribbon 超时机制_第5张图片

Ribbon 的默认配置在下面这里:

一次线上超时问题,看Ribbon 超时机制_第6张图片

三、总结

如果上面图看的有点晕,那下面这张图一定让你茅塞顿开:

一次线上超时问题,看Ribbon 超时机制_第7张图片

总结一句话: Feign 集成了 Ribbon, 通过 LoadBalancerFeignClient 直接调用,而 LoadBalancerFeignClient 又通过代理 OkhttpClient (这里是feign包里的),继续往下代理,会调用真正的 okhttp3.OkHttpClient。

参数配置优先级:feign 没有配置会使用ribbon的,否则会使用 feign 配置的,如果feign 配置的和 okhttp3.OkHttpClient 参数不一致,会使用 feign 配置的!


如果觉得还不错的话,关注、分享、在看, 原创不易,且看且珍惜~

 

你可能感兴趣的:(源码,MSA,分布式,ribbon,java,服务器)