背景:

我们有个基于oauth2.0协议给第三方授权以及信息的业务,年前对接入层、业务层做了次迁移。业务架构简单介绍下:
lvs接入---> nginx ---> tomcat
 
问题:
迁移完第1天,接到好几个合作商的投诉,其中有家说在他们业务集群中,有20%左右的失败率,日志显示连接被拒绝。

定位:
和开发商调试,telnet我方端口正常。curl发测试请求也正常。没办法,请开发商的运维同学tcpdump抓了几分钟的数据,
发过来分析。如下图

打开一看全是灰色...怪吓人的。从抓包看被server端rst的数据包也不少,这个就是为啥有20%左右连接被拒绝了。看这些
请求基本就是发出syn后server没回包。看到这个就有点怀疑server端是不是开启了tcp_tw_recycle和tcp_timestamps,马
上登录RS nginx机器查看,果然是打开的。把tcp_tw_recycle关闭,再联系开发商观察日志。ok了!

原因:
在TCPIP的标准RFC 1323里有这样的定义:
  An additional mechanism could be added to the TCP, a per-host
  cache of the last timestamp received from any connection.
  This value could then be used in the PAWS mechanism to reject
  old duplicate segments from earlier incarnations of the
  connection, if the timestamp clock can be guaranteed to have
  ticked at least once since the old connection was open.  This
  would require that the TIME-WAIT delay plus the RTT together
  must 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)过来的连接最新的timestamp值。这个缓存的值
可以用于PAWS(Protect Against Wrapped Sequence numbers,是一个简单的防止重复报文的机制)中,来丢弃当前连
接中可能的旧的重复报文。而Linux实现这个机制的方法就是同时启用net.ipv4.tcp_timestamps和net.ipv4.tcp_tw_recycle
这两个选项。

这种机制在 客户端-服务器 一对一的时候,没有任何问题,但是当服务器在负载均衡器后面时,由于负载均衡器不会修改
包内部的timestamp值,而互联网上的机器又不可能保持时间的一致性,再加上负载均衡是会重复多次使用同一个tcp端口
向内部服务器发起连接的,就会导致什么情况呢:

负载均衡通过某个端口向内部的某台服务器发起连接,源地址为负载均衡的内部地址——同一ip
假如恰巧先后两次连接源端口相同,这台服务器先后收到两个包,第一个包的timestamp被服务器保存着,第二个包又来了,
一对比,发现第二个包的timestamp比第一个还老——客户端时间不一致。服务器基于PAWS,判断第二个包是重复报文,
丢弃之
反映出来的情况就是在服务器上抓包,发现有SYN包,但服务器就是不回ACK包,因为SYN包已经被丢弃了。为了验证这
一结果,可以执行netstat -s | grep timestamp 命令,看输出里面passive connections rejected by timestamp 一项的数字变化。


参考:
1. http://saview.wordpress.com/2011/09/27/tcp_tw_recycle%E5%92%8Cnat%E9%80%A0%E6%88%90syn_ack%E9%97%AE%E9%A2%98/
posted on 2015-08-26 13:45  jdonson  阅读(1321)  评论(0编辑  收藏  举报