linux服务器开发中网络数据分析与故障排查( 四 )


linux服务器开发中网络数据分析与故障排查

文章插图
 
这个时候客户端发送SYN , 服务器应答ACK+RST:
linux服务器开发中网络数据分析与故障排查

文章插图
 
这个应答包会导致客户端的connect连接失败 。
还有一种情况就是客户端访问一个很遥远的ip , 或者网络繁忙 , 服务器对客户端发送的网络SYN报文没有应答 , 会出现什么情况呢?
linux服务器开发中网络数据分析与故障排查

文章插图
 
我们先将防火墙的已有规则都清理掉: iptables -F
然后给防火墙的INPUT链上增加一个规则 , 丢弃本地网卡lo(也就是127.0.0.1这个回环地址)上的所有SYN包 。
linux服务器开发中网络数据分析与故障排查

文章插图
 
接着 , 我们看到tcpdump抓到的数据包如下:
linux服务器开发中网络数据分析与故障排查

文章插图
 
连接不上 , 一共重试了5次 , 重试的时间间隔是1秒 , 2秒 , 4秒 , 8秒 , 16秒 , 最后返回失败 。这个重试次数在/proc/sys/net/ipv4/tcp_syn_retries 内核参数中设置 , 默认为6 。
四次挥手与三次握手基本上类似 , 这里就不贴出tcpdump抓包的详情了 。实际的网络开发中 , 尤其是高QPS的服务器程序 , 可能在在服务器程序所在的系统上留下大量非ESTABLISHED的中间状态 , 如CLOSE_WAIT/TIME_WAIT , 我们可以使用以下指令来统计这些状态信息:
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
得到结果可能类似:
linux服务器开发中网络数据分析与故障排查

文章插图
 
让我们再贴一张tcp三次握手和四次挥手更清晰的图吧 。
linux服务器开发中网络数据分析与故障排查

文章插图
 
下面看下一般比较关心的三种TCP状态
  • SYN_RECV
服务端收到建立连接的SYN没有收到ACK包的时候处在SYN_RECV状态 。有两个相关系统配置:
1、net.ipv4.tcp_synack_retries , 整形 , 默认值是5
对于远端的连接请求SYN , 内核会发送SYN + ACK数据报 , 以确认收到上一个 SYN连接请求包 。这是三次握手机制的第二个步骤 。这里决定内核在放弃连接之前所送出的 SYN+ACK 数目 。不应该大于255 , 默认值是5 , 对应于180秒左右时间 。通常我们不对这个值进行修改 , 因为我们希望TCP连接不要因为偶尔的丢包而无法建立 。
2、net.ipv4.tcp_syncookies
一般服务器都会设置net.ipv4.tcp_syncookies=1来防止SYN Flood攻击 。假设一个用户向服务器发送了SYN报文后突然死机或掉线 , 那么服务器在发出SYN+ACK应答报文后是无法收到客户端的ACK报文的(第三次握手无法完成) , 这种情况下服务器端一般会重试(再次发送SYN+ACK给客户端)并等待一段时间后丢弃这个未完成的连接 , 这段时间的长度我们称为SYN Timeout , 一般来说这个时间是分钟的数量级(大约为30秒-2分钟) 。这些处在SYNC_RECV的TCP连接称为半连接 , 并存储在内核的半连接队列中 , 在内核收到对端发送的ack包时会查找半连接队列 , 并将符合的requst_sock信息存储到完成三次握手的连接的队列中 , 然后删除此半连接 。大量SYNC_RECV的TCP连接会导致半连接队列溢出 , 这样后续的连接建立请求会被内核直接丢弃 , 这就是SYN Flood攻击 。能够有效防范SYN Flood攻击的手段之一 , 就是SYN Cookie 。SYN Cookie原理由D. J. Bernstain和 Eric Schenk发明 。SYN Cookie是对TCP服务器端的三次握手协议作一些修改 , 专门用来防范SYN Flood攻击的一种手段 。它的原理是 , 在TCP服务器收到SYN包并返回SYN+ACK包时 , 不分配一个专门的数据区 , 而是根据这个SYN包计算出一个cookie值 。在收到ACK包时 , TCP服务器在根据那个cookie值检查这个TCP ACK包的合法性 。如果合法 , 再分配专门的数据区进行处理未来的TCP连接 。观测服务上SYN_RECV连接个数为:7314 , 对于一个高并发连接的通讯服务器 , 这个数字比较正常 。
  • CLOSE_WAIT
发起TCP连接关闭的一方称为client , 被动关闭的一方称为server 。被动关闭的server收到FIN后 , 但未发出ACK的TCP状态是CLOSE_WAIT 。出现这种状况一般都是由于server端代码的问题 , 如果你的服务器上出现大量CLOSE_WAIT , 应该要考虑检查代码 。


推荐阅读