SpringCloud使用OpenFeign+sentinel时,遇到Read timed out

现象:

在这里插入图片描述

分析

在这里插入图片描述

从上面的异常提示中可以看出,产生了一个Read time out,但是在配置文件中已经配置了read-timeout为120000ms,但是没起到任何作用,本次调用只是花费了2241ms,所以完全不应该超时。后来偶然间加上了connect-timeout配置,read-timeout配置才生效,如下代码所示:

feign:
  sentinel:
    enabled: true
  hystrix:
    enabled: false
  client:
    config:
      default:
        connect-timeout: 120000
        read-timeout: 120000

根本原因是,openfeign在对超时时间判断时,将connect-timeout和 read-timeout进行&&判断,必须同时存在,否则只配置了其中的任何一个,并不会生效,部分源码如下所示(重点关注if (config.getConnectTimeout() != null && config.getReadTimeout() != null));

protected void configureUsingProperties(
			FeignClientProperties.FeignClientConfiguration config,
			Feign.Builder builder) {
		if (config == null) {
			return;
		}

		if (config.getLoggerLevel() != null) {
			builder.logLevel(config.getLoggerLevel());
		}

		if (config.getConnectTimeout() != null && config.getReadTimeout() != null) {
			builder.options(new Request.Options(config.getConnectTimeout(),
					config.getReadTimeout()));
		}

		if (config.getRetryer() != null) {
			Retryer retryer = getOrInstantiate(config.getRetryer());
			builder.retryer(retryer);
		}

		if (config.getErrorDecoder() != null) {
			ErrorDecoder errorDecoder = getOrInstantiate(config.getErrorDecoder());
			builder.errorDecoder(errorDecoder);
		}

		if (config.getRequestInterceptors() != null
				&& !config.getRequestInterceptors().isEmpty()) {
			// this will add request interceptor to builder, not replace existing
			for (Class<RequestInterceptor> bean : config.getRequestInterceptors()) {
				RequestInterceptor interceptor = getOrInstantiate(bean);
				builder.requestInterceptor(interceptor);
			}
		}

		if (config.getDecode404() != null) {
			if (config.getDecode404()) {
				builder.decode404();
			}
		}

		if (Objects.nonNull(config.getEncoder())) {
			builder.encoder(getOrInstantiate(config.getEncoder()));
		}

		if (Objects.nonNull(config.getDecoder())) {
			builder.decoder(getOrInstantiate(config.getDecoder()));
		}

		if (Objects.nonNull(config.getContract())) {
			builder.contract(getOrInstantiate(config.getContract()));
		}

		if (Objects.nonNull(config.getExceptionPropagationPolicy())) {
			builder.exceptionPropagationPolicy(config.getExceptionPropagationPolicy());
		}
	}

补充

引起Read timed out有很多种原因,此处只列举了一种,如果您也正好使用的是SpringCloud+OpenFeign(ribbon)+Sentinel(使用它做了调用异常处理),可以复制以下的超时配置,设定的连接和读超时时间都为12000毫秒(可以进行修改)。

feign:
  sentinel:
    enabled: true
  hystrix:
    enabled: false
  client:
    config:
      default:
        connect-timeout: 120000
        read-timeout: 120000

我能想到的几种可能是,
1.同时开启了hystrix,那么需要增加hystrix的超时配置
2.同时配置 Feign 和 Ribbon 的超时,以Feign为准
3.注意connect-timeout, read-timeout参数写法,如果是驼峰模式,首字母需要大写


版权声明:本文为qq_36729737原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。