排查okhttp3的unexpected end of stre

2021-06-30  本文已影响0人  小胖学编程

某个微服务上线后,经常抛出unexpected end of stream on Connection异常。怀疑是服务端断开长链接,而客户端依旧使用该连接调用。

调用链路如图所示:

image.png

1. 临时方案

根据异常信息定位到:服务端长链接失效。客户端依旧使用失效的长链接去访问。

当前的解决方案是:增加重试机制:retryOnConnectionFailure(true),当客户端使用失效的长链接访问服务器失败时,重新访问。

但是这个是临时的解决方案,可以使得业务不受影响,但是依旧无法解决服务端长链接失效的问题。

2. 问题分析

2.1 服务端长链接失效时间

登录服务器(因为是微服务调用,服务器自己是可以登录上的)。

cat /proc/sys/net/ipv4/tcp_keepalive_time

但得到的结果是默认的7200秒。

2.2 wireshark抓包分析

登录服务器,使用tcpdump命令抓包分析,工具的使用详见——TCP抓包分析—以及wireshark工具下载使用

image.png

三次握手和四次挥手的文章

  1. 客户端经过3次握手过程和服务端建立长链接;
  2. 在8s内长链接没有请求,服务端发起了四次挥手(FIN);
  3. 客户端收到FIN后,发送ACK确认收到;
  4. 客户端通知应用程序是否给服务器发送FIN时;okhttp3使用该连接进行通信;
  5. 发生RST过程,于是抛出了上述的异常。

下面是一个链接正常的建立和销毁:

image.png

可以看到,当该链接8s内无数据时,服务端会主动的断开连接。

由上述抓包分析可知:关键点8s内无请求访问,服务器断开长链接;

3.2 代码配置排查

项目使用的是SpringCloud全家桶进行开发。替换了tomcat服务器使用了undertow服务器。Spring Boot 内嵌容器Undertow取代tomcat

查看配置信息时,发现:

org.springframework.boot.autoconfigure.web.ServerProperties.Undertow配置地址:

image.png

由此可知:

  1. 服务器是否开启长链接由alwaysSetKeepAlive控制;
  2. 当一个链接noRequestTimeout内空闲,服务器便会关闭链接;

如代码所示:

image.png

当server的worker在noRequestTimeout空闲时,便会shutdown该链接。于是改链接向客户端发起FIN配置。

3.3 问题解决

也就是设置noRequestTimeout便可以去解决:服务器关闭长链接的问题。但是配置文件中未设置该参数,这个8s是在哪里来的?

经过排查发现,配置文件中存在下列配置:

server:
  connection-timeout: 8000

源码位置:org.springframework.boot.autoconfigure.web.embedded.UndertowWebServerFactoryCustomizer#customize

image.png

也就是设置了connection-timeout超时时间影响了服务端长连接关闭的时间。

最终解决方案:

server:
  connection-timeout: 60000 # 默认60s,此时显式的设置为60s。
上一篇下一篇

猜你喜欢

热点阅读