3

CentOS系统里TCP状态中TIME_WAIT超过3万的分析与建议

 4 years ago
source link: http://www.eryajf.net/4147.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
CentOS系统里TCP状态中TIME_WAIT超过3万的分析与建议 |坐而言不如起而行! 二丫讲梵
> 迎刃而解 > CentOS系统里TCP状态中TIME_WAIT超过3万的分析与建议
本文预计阅读时间 4 分钟

通过如下命令,我们可以看到系统当中TCP状态中的情况:

  1. $ netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'
  2. LAST_ACK 192
  3. SYN_RECV 97
  4. CLOSE_WAIT 2
  5. ESTABLISHED 14418
  6. FIN_WAIT1 389
  7. FIN_WAIT2 1706
  8. SYN_SENT 2
  9. CLOSING 51
  10. TIME_WAIT 17697

当然了,如果我们配置了系统监控,那么从Prometheus中看系统TCP状态会更加清晰。

主机上的TCP状态的TIME_WAIT数非常高,在三万到五万之间徘徊,这是相当高的,在分析问题原因以及给出解决方案之前,先来理解一下这个TIME_WAIT是个什么东东。

我们的应用对外提供服务,当 TCP 连接主动关闭时,都会经过 TIME_WAIT 状态。TCP 四次握手结束后,连接双方都不再交换消息,但主动关闭的一方会保持这个连接在一段时间内不可用。

那么,保持这么一个状态有什么用呢?

为了理解 TIME_WAIT 状态的必要性,我们先来假设没有这么一种状态会导致的问题。暂以 A、B 来代指 TCP 连接的两端,A 为主动关闭的一端。

  • 四次挥手中,A 发 FIN, B 响应 ACK,B 再发 FIN,A 响应 ACK 实现连接的关闭。而如果 A 响应的 ACK 包丢失,B 会以为 A 没有收到自己的关闭请求,然后会重试向 A 再发 FIN 包。

此时,如果没有 TIME_WAIT 状态,A 不再保存这个连接的信息,收到一个不存在的连接的包,A 会响应 RST 包,导致 B 端异常响应。

此时, TIME_WAIT 是为了保证全双工的 TCP 连接正常终止。

我们还知道,TCP 下的 IP 层协议是无法保证包传输的先后顺序的。如果双方挥手之后,一个网络四元组(src/dst ip/port)被回收,而此时网络中还有一个迟到的数据包没有被 B 接收,A 应用程序又立刻使用了同样的四元组再创建了一个新的连接后,这个迟到的数据包才到达 B,那么这个数据包就会让 B 以为是 A 刚发过来的。

从如上内容的分析中,我们在解决此类问题的时候,大致有两个方向可走,一个是控制一个TCP连接流程在系统当中的最大时间,一个是分配的time_wait容量池的最大容量,从这两个角度入手,一般就能比较好的控制系统当中time_wait的数量。

而上边说到的这两个参数,则都是在内核参数当中进行配置定义的。在sysctl.conf当中定义如下参数:

  1. net.ipv4.tcp_fin_timeout = 20 # 设置单条TCP超时时间为20s,centos中默认为30s
  2. net.ipv4.tcp_max_tw_buckets = 19400

在网上一些文章中,有建议将 net.ipv4.tcp_max_tw_buckets这个参数往大了调的,这种建议呢,或许在业务量小,没跑出系统性能的情况下,是合适的,但是如果在业务量庞大的场景下,我是不建议使劲儿把这个参数往大了调的,如果设置的过大(超过常规的65535),那么很可能会影响正常的TCP请求,因此应该自行斟酌将此值设置在一个合理的范围当中。


weinxin


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK