• @FeignClient注解配置局部超时时间和踩坑记 SocketTimeoutException异常解决办法


    问题描述:open feign配置OKhttp调用远程API,连续调用次数较少时,一切正常,次数非常多时(例如,连续请求600次)就抛出java.net.SocketTimeoutException: timeout,关键信息如下:

    Caused by: java.net.SocketTimeoutException: timeout
      at okhttp3.internal.http2.Http2Stream$StreamTimeout.newTimeoutException(Http2Stream.kt:662)
      at okhttp3.internal.http2.Http2Stream$StreamTimeout.exitAndThrowIfTimedOut(Http2Stream.kt:671)
      at okhttp3.internal.http2.Http2Stream$FramingSource.read(Http2Stream.kt:377)
      at okhttp3.internal.connection.Exchange$ResponseBodySource.read(Exchange.kt:279)
      at okio.RealBufferedSource.read(RealBufferedSource.kt:41)
      at okio.RealBufferedSource.exhausted(RealBufferedSource.kt:51)
      at okio.InflaterSource.refill(InflaterSource.kt:94)
      at okio.InflaterSource.read(InflaterSource.kt:54)
      at okio.GzipSource.read(GzipSource.kt:69)
      at okio.RealBufferedSource$inputStream$1.read(RealBufferedSource.kt:438)
      at java.io.FilterInputStream.read(FilterInputStream.java:133)
      at java.io.PushbackInputStream.read(PushbackInputStream.java:186)
      at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
      at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
      at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
      at java.io.InputStreamReader.read(InputStreamReader.java:184)
      at java.io.Reader.read(Reader.java:140)
      at org.springframework.util.StreamUtils.copyToString(StreamUtils.java:91)
      at org.springframework.http.converter.StringHttpMessageConverter.readInternal(StringHttpMessageConverter.java:96)
      at org.springframework.http.converter.StringHttpMessageConverter.readInternal(StringHttpMessageConverter.java:44)
      at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:199)
      at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:114)
      ... 15 common frames omitted
    

    使用spring java config 进行局部属性配置,OKhttp基本配置代码如下所示:

    /**
     * @author 楼兰胡杨
     */
    public class FeignConfig {
    
        private final static int READ_TIMEOUT = 10;
        private final static int MAX_IDLE_CONNECTIONS = 200;
        private final static int CONNECT_TIMEOUT = 30;
        private final static int WRITE_TIMEOUT = 35;
    
    
        /**
         *  客户端配置
         *
         */
        @Bean
        public OkHttpClient okHttpClient() {
            OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
            //读取超时时间
            clientBuilder.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS);
            //连接超时时间
            clientBuilder.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);
            //写入超时时间
            clientBuilder.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS);
    
            //默认最大5个空闲连接
            clientBuilder.connectionPool(new ConnectionPool(MAX_IDLE_CONNECTIONS, READ_TIMEOUT, TimeUnit.MINUTES));
    
            return clientBuilder.build();
        }
    }
    

      FeignConfig类上切勿添加@Component注解,一旦添加,它将变成全局配置,这里只用作局部配置。当然,我们在yaml配置文件中已经开启了OKhttp支持:

    # 默认关闭,现开启
    feign.okhttp.enabled=true
    

    由@FeignClient注解的configuration属性配置这个API接口类的特殊属性,feign client代码如下:

    @FeignClient(name = "feignApi", url = "${self.your.url}", configuration = FeignConfig.class)
    public interface FeignApiClient {
    
        @PostMapping(value = "/xxx")
        String query(@RequestBody ParamDTO dto);
      
    }
    

    问题分析:连续请求次数比较少时,一切正常,说明配置OKhttp基本配置没有问题,而连续请求次数非常多(例如600+次)时就出问题,说明TCP连接时间超过了对方TCP长连接有效期,导致抛出异常。

    解决办法把TCP长连接改为短连接,设置headers 属性 {"Connection=close"}。不论客户端还是服务端的header,只要包含了值为close的connection,都表明当前正在使用的TCP连接在本次请求处理完毕后会被断掉,以后客户端再进行请求时,就必须创建新的TCP连接,而非复用,从而避开TCP长连接有效期的约束。优化后,query函数代码如下:

    @FeignClient(name = "feignApi", url = "${self.your.url}", configuration = FeignConfig.class)
    public interface FeignApiClient {
        @PostMapping(value = "/xxx", headers = {"Connection=close"})
        String query(@RequestBody ParamDTO dto);
      
    }
    

      关于TCP长连接和短连接的介绍,请戳《http协议中长连接和短连接介绍》。 老铁们, 因个人能力有限,难免有瑕疵,如果发现bug或者有更好的建议,那么请在文章下方留言!

  • 相关阅读:
    ACM题目————食物链
    ACM题目————Find them, Catch them
    hdu 1255 覆盖的面积 (线段树处理面积覆盖问题(模板))
    poj 3373 Changing Digits (DFS + 记忆化剪枝+鸽巢原理思想)
    hdu 3303 Harmony Forever (线段树 + 抽屉原理)
    hdu 2665 Kth number(划分树模板)
    poj 1348 Computing (四个数的加减乘除四则运算)
    hdu 1021 Fibonacci Again(找规律)
    HDU 1560 DNA sequence (IDA* 迭代加深 搜索)
    hdu 1560 DNA sequence(搜索)
  • 原文地址:https://www.cnblogs.com/east7/p/15856748.html
Copyright © 2020-2023  润新知