问题背景
生产环境与第三方联通时,时常有丢包的情况发生,具体现象为有时候应用服务器表现为未收到报文,抓包表现为RST
生产环境通讯方式为https,应用前端有SSL 及 F5负载,业务入口有NAT转换,然后经过SSL卸载https,http请求经F5负载均衡至两台应用服务。
问题分析
因为报文链路有点长,发起的客户端报错为未收到服务端返回,但服务端的表现为未收到交易,这就只能做抓包处理了
客户端报错分析
Unexpected end of file from server 服务器意外的文件结束
导致这个问题出现的直接原因是返回的数据丢包了,所以出现这个错误。
根本原因可能有三:
- 服务端的程序代码有问题;
- 网络链路中的某个网络设备有故障,如SSL或者F5;
- 网络设备安全策略配置的原因,比如IP限制,恶意扫描拒绝等,当不符合安全策略的时候,数据包被直接丢弃;
- 服务端代码有问题
如果是代码问题的话,那应该是特定场景,特定的情况会出现,但该问题是随机出现,并不是特定的情况,时好时坏。 - 网络链路设备问题
经过抓包网络链路设备收到报文后,均向后方进行了转发,但被后方拒绝 - 网络设备安全策略配置问题
这个非常可能了,某种情况导致服务端丢弃数据包,我们也就从这个角度详细去查了
服务端情况分析
服务端应用没有对应报文进入的日志,但网络设备已经进行转发,可以判断对应的问题应该出在应用服务器的某些配置,但与应用代码无关,跟linux服务器配置或者网络防火墙相关的配置有关。
问题解决
1、检查防火墙配置
为了查询问题,直接关闭了防火墙
2、检查sysctl中ipv4相关参数
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_timestamps = 1
....
3、检查linux对应ssh参数
...
最终问题定位
最终发现为sysctl中参数问题,修改如下
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_timestamps = 0
....
不同时开启tcp_timestamps和tcp_tw_recycle的场景描述
FULL NAT下
FULL NAT 在client请求VIP 时,不仅替换了package 的dst ip,还替换了package的 src ip;但VIP
返回给client时也替换了src iplvs后端为web服务器。
假如web服务器开启了tcp的tcp_timestamps和tcp_tw_recycle这两个参数。那么存在下面这种情况
RFC1323中有如下一段描述:
An additional mechanism could be added to the TCP, a per-hostcache of
the last timestamp received from any connection.This value could then
be used in the PAWS mechanism to rejectold duplicate segments from
earlier incarnations of theconnection, if the timestamp clock can be
guaranteed to haveticked at least once since the old connection was
open. Thiswould require that the TIME-WAIT delay plus the RTT
togethermust be at least one tick of the sender’s timestamp clock.Such
an extension is not part of the proposal of this RFC.大概意思是说TCP有一种行为,可以缓存每个连接最新的时间戳,后续请求中如果时间戳小于缓存的时间戳,即视为无效,相应的数据包会被丢弃。意思就是同一个源IP来连接同一个目的端口的数据包时间戳必须是递增的
Linux是否启用这种行为取决于tcp_timestamps和tcp_tw_recycle,因为tcp_timestamps缺省就是开启的,所以当tcp_tw_recycle被开启后,实际上这种行为就被激活了。
现在很多公司都用LVS做负载均衡,通常是前面一台LVS,后面多台后端服务器,这其实就是NAT,当请求到达LVS后,它修改地址数据后便转发给后端服务器,
但不会修改时间戳数据,对于后端服务器来说,请求的源地址就是LVS的地址,加上web端口会复用,所以从后端服务器的角度看,原本不同客户端的请求经过LVS的转发,
就可能会被认为是同一个连接,加之不同客户端的时间可能不一致,所以就会出现时间戳错乱的现象,于是后面的数据包就被丢弃了,
具体的表现通常是是客户端明明发送的SYN,但服务端就是不响应ACK,还可以通过下面命令来确认数据包不断被丢弃的现象
注意点
- tw_reuse,tw_recycle 必须在客户端和服务端timestamps 开启时才管用(默认打开),其实意思就是假如服务端和客户端两边有一边timestamps没开启。tw_reuse和tw_recycle都没啥作用
- tw_reuse 只对客户端起作用,开启后客户端在1s内回收。reuse就是重用time_wait的socket连接。 服务端同一个端口被连接理论上是没限制的。
- tw_recycle 对客户端和服务器同时起作用,开启后在 3.5*RTO 内回收,RTO 200ms~ 120s 具体时间视网络状况。 内网状况比tw_reuse 稍快,公网尤其移动网络大多要比tw_reuse
慢,优点就是能够回收服务端的TIME_WAIT数量
对于客户端
- 作为客户端因为有端口65535问题,TIME_OUT过多直接影响处理能力,打开tw_reuse 即可解决,不建议同时打开tw_recycle,帮助不大。
- tw_reuse 帮助客户端1s完成连接回收,基本可实现单机6w/s请求,需要再高就增加IP数量吧。
- 如果内网压测场景,且客户端不需要接收连接,同时tw_recycle 会有一点点好处。
对于服务端
- 打开tw_reuse无效,因为是客户端连接web服务器,服务端肯定不会重用socket去主动连接客户端。这个参数服务器一般用不到,除非web服务器又作为客户端去连接后端数据库才用到。
但是web服务器作为客户端连接数据库达到6万端口的限制时你的数据库早承受不了压力瘫痪了。一般数据库5000连接数就已经很高了。
tw_resue这个参数,只有客户端用得到。意思就是重用处于time_wait的socket连接。
- 线上环境 tw_recycle 不要打开 服务器处于NAT 负载后,或者客户端处于NAT后(这是一定的事情,基本公司家庭网络都走NAT);
公网服务打开就可能造成部分连接失败,内网的话到时可以视情况打开; 有些负载均衡设备会把timestamp
都给清空,后端web服务器开启不开启tw_recycle都无所谓了。- 服务器TIME_WAIT 高怎么办
服务器time_wait不用担心,因为我是服务端,是客户端很多IP和端口主动连接我的一个端口,比如连接我的80端口。很可能出现一种情况就是虽然我机器上有10万个time_wait连接。但是我的端口才用到一个80端口。
不像客户端有端口限制,处理大量TIME_WAIT Linux已经优化很好了,每个处于TIME_WAIT 状态下连接内存消耗很少,
而且也能通过tcp_max_tw_buckets = 262144 配置最大上限,现代机器一般也不缺这点内存。
总结下来
总之,生产中,服务器不管有没有在nat设备后面.
tcp_tw_recycle不开启就行了。默认就是不开启的状态,值为0
tcp_timestamps保持默认开启就行了,值为1
tcp_tw_reuse.客户端最好开启。负载均衡设备连接web服务器时,辅助均衡设备也尽量开启
关于服务器端出现大量time_wait,有些人会问,我是web服务器端,为什么会出现客户端那种time_wait。
其实关于time_wait,它是出现在主动请求关闭连接的那一段。 服务器主动关闭http的连接。它就转变为了客户端。
发起断开连接这个动作,不是说就一定是客户端发起断开的。很多时候都是服务器端先发起断开连接操作。比如很多http服务器,短连接。很多时候服务器主动断开。
服务出现tcp连接问题可以先查看下下面,看看是否有很多,很多时候就是开启了tcp_tw_recycle导致的