https://img.ffutop.com/2E00BD7E-3EE2-4E3E-A74F-DD41320ED1A1.png

TCP 状态无外乎图中的 11 种。通过 netstat -nat 命令可以观察到所有 TCP 连接(包括 TCP 监听)。一般来说,SYN_RCVD、SYN_SENT、FIN_WAIT_1、FIN_WAIT_2、CLOSING、CLOSE_WAIT、LAST_ACK、CLOSED 都是瞬态,在大量 TCP 连接中,只会观测到极少数这些状态。一个健康的系统通常是一些 LISTEN 状态的监听,大量 ESTABLISHED 状态的 TCP 连接配合少量 TIME_WAIT 状态的 TCP 连接。

一旦大量观察到 SYN_RCVD、SYN_SENT、FIN_WAIT_1、FIN_WAIT_2、CLOSING、CLOSE_WAIT、LAST_ACK、CLOSED 这些状态,系统陷入异常,如何有效分析状态的成因就至关重要。

建立连接过程

SYN_SENT

SYN_SENT 发生在客户端与服务端建立连接的过程中,TCP 三次握手建立连接过程一般是迅速的,整个过程只需要一个 RTT (Round-trip time,往返时间)。

如果观察到 TCP 连接长时间处于 SYN_SENT 状态,可能的原因包括:

  • 目的 IP 不可达
  • 网络链路丢包严重
  • 目的端口未打开

SYN_RCVD

SYN_RCVD 发生在服务端接收到客户端发送的 SYN,响应 SYN+ACK 包,并等待客户端回复 ACK 包时。这个状态一般也是短暂的。

如果观察到大量 TCP 连接长期处于 SYN_RCVD 状态,一般认为是遭到 SYN 洪泛攻击。通过占用服务端的半连接队列,使得正常连接无法被建立。

断开连接过程

以建立连接的主客体划分客户端与服务端,断开连接可以由客户端发起,也可以由服务端发起,当然,也可以同时发起。

一般来说,客户端会主动断开连接,以释放对服务端资源的占用。

下述场景如无特别说明,均认为客户端会主动断开连接。

CLOSE_WAIT

CLOSE_WAIT 状态发生在服务端收到客户端发送的 FIN 包,响应 ACK 之后。

如果观察到大量 TCP 连接长期处于 CLOSE_WAIT 状态,基本可以判断客户端未收到响应等待超时,请求未被服务端处理或正在处理中。

可能的情况如下:

  • 服务端工作线程同步等待第三方资源,无法处理其他请求
  • 服务端工作线程发生死锁,无法处理其他请求
  • 服务端工作线程异常死亡,未补充新的工作线程,无法处理其他请求
  • 等等…

总之,供小于求,服务端的连接积压会不断累积,知道服务崩溃或人工干预。

LAST_ACK

LAST_ACK 状态发生 CLOSE_WAIT 状态之后,服务端向客户端发送 FIN 包,未收到 ACK 时。状态一般只持续一个 RTT 。

如果大量观察到 LAST_ACK,请直接忽略。这个状态对判断系统问题毫无助益,只能说明系统在自恢复过程中碰到了网络包无法到达客户端的情况。