解决接口响应超时Socket read time out
首先下面这个就是万恶之源Time out
`java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:170)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:137)
at org.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:153)
at org.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:280)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:138)
首先要知道的是这个报错是发生在我使用Fein调用另一个服务的时候,由于服务端执行时间比较久导致服务之间的socket链接断开了,而且观察到断开的时候每次都是60000ms左右,所以可以猜测的是 肯定有某个地方设置了这个60秒。
判断是客户端的配置还是服务端的配置
接下来就要分析是客户端的配置还是服务端的,所以我使用postman模拟接口调用重新请求了服务端,发现即使超过了60秒也不会自动断开,那么可以肯定的就是这个配置在客户端了
客户端配置请求超时时间
我的架构是springcloud一套,也就是用了feign ,hystrix ,ribbon,所以在网上搜到了关于feign 和ribbon 的超时设置:
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 3000
ribbon:
OkToRetryOnAllOperations: false #对所有操作请求都进行重试,默认false
ReadTimeout: 5000 #负载均衡超时时间,默认值5000
ConnectTimeout: 3000 #ribbon请求连接的超时时间,默认值2000
MaxAutoRetries: 0 #对当前实例的重试次数,默认0
MaxAutoRetriesNextServer: 1 #对切换实例的重试次数,默认1
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 600000
strategy: THREAD
在这里需要知道的两个超时的概念一个是readtimeout,一个connecttimeout, connecttimeout 是指客户端在请求连接服务端的时候的一个超时时间,readtimeout是指连接成功之后等待服务端response的时间,或者是指与服务端进行数据传输的时间。那么针对我的报错那一定就是修改readtimeout了,愁情稍微延长应该可以解决问题。hystrix的 timeout是指整个接口调用的最外层的超时时间,所以需要大于ribbon的重试时间总和。
在了解到这些属性之后我以为就这样结束了。。。
结果并没有,当我尝试接口调用的时候发现无论我怎么设置ribbon和feign的超时时间都不会生效,仍然还是60秒超时结束。一度让我怀疑这个socket read time out 可能和feign的设置没关系,网上再找发现还有人设置mvc的请求超时时间
spring:
mvc:
async:
request-timeout: 300000
还有尝试设置tomcat的连接超时时间。。。。
各种能设置的都找遍以后还是不生效,最后只能老实debug看源码了…
HttpClientFeignLoadBalancedConfiguration feign整合httpclient启动配置类
一个比较核心的配置,顺腾摸瓜找到LoadBalancerFeignClient类里面的execute,是当我们调用feign接口时回来调用的一个方法,这个方法里面两个参数,第二参数就是关于超时的配置
在excute方法的64行会去拿这个配置的value与默认值作比较
再点开这个默认值 惊奇的发现 就是这个60秒,这个时间其实时feign接口调用的一个默认超时时间,如果有配置的话就会使用配置,但是我都配置了 在debug的时候发现传参过来的还是默认值!!
所以现在的问题最终就变成了 只要找出为什么没有正常的将配置传参过来就解决了。
feign接口调用底层时默认使用了ribbon的,所以在继续往上debug我找到了这个类:FeignRibbonClientAutoConfiguration
这个类看名字知道是feign调用时的负载均衡的一个配置类,昂我有意外收获的是 在最下面,有一个对Options的Bean的注入,也就是说上面这个默认的超时时间也就是在这里开始注入的,并且还有@ConditionalOnMissingBean 这个注解
所以我直接新建了一个config类重新注入Options 的Bean
最后,重启,测试,调用 ,3秒time out ,生效了!!!
所以,其实最终Socket time out 这个接口调用时的异常 实际上还是因为feign 接口调用的客户端设置的readtimeout属性来控制的,虽然我使用重新注入的方式解决了问题,但是yml配置ribbon不生效的问题 我还需要继续分析,也算有一些收获,就在次记录一下这个问题把。