1. 问题描述
客户端A --> Ngnix --> 服务B
Ngnix做服务B的负载,客户端访问服务B时,客户端偶尔会有抛出TimeoutException异常。
举个例子:如A在09:59:48访问B,则服务B在09:59:53收到请求,并成功执行业务并返回。但是A会在10:00:05左右抛出TimeoutException。此时客户端A认为本次调用失败,然后走失败的业务逻辑。但是查找服务端的日志,发现实际业务在服务B上正常执行了,并正常返回。这样出现客户端和服务端两边数据不一致的问题。
这个问题是难点:
- 两边是通过公网调用,公网网络的复杂性会导致问题更复杂
- 无法直接定位是服务端还是客户端的问题
- 两边的程序不是同一个所写,由不同人维护。自己维护服务端代码,客户端代码是其它人维护
- 需要理解TCP/IP的通信协议
- 需要理解httplclent和ngnix的超时配置相关的知识
下面我按照以下顺序一一排查问题:
- 网络问题
- 超时配置参数的问题
- GC的问题
- 使用tcpdump抓包,分析网络包
- 修正代码问题
- 上线验证
2. 问题分析处理的过程
2.1. 网络问题
由于客户端A和服务B是使用公网访问,最开始认为是网络抖动引起,并没有马上处理。但是运行一段时间后且这段时间服务器的流量不是很大,这个问题仍然每天不定时出现,所以猜测可能不是网络的问题。
2.2. 超时配置参数的问题
又猜测可能是超时参数配置的问题。整理服务端和客户端配置如下:
客户端httpclient
客户端httpclient的关于连接的配置相关的参数和意义如下:
- SocketTimeout 是 5s
- 连接建立后,数据传输过程中数据包之间间隔的最大时间
- ConnectTimeout 是 3s
- 连接建立时间,即三次握手完成时间
- ConnectionRequestTimeout 是默认值
- httpclient使用连接池来管理连接,这个时间就是从连接池获取连接的超时时间
这3个属性的关系如下:下图来自网络