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,请直接忽略。这个状态对判断系统问题毫无助益,只能说明系统在自恢复过程中碰到了网络包无法到达客户端的情况。