Skip to content

模块导航: 总入口 · 总纲与方法 · 后端场景 · AI与算法工程 · 国企与金融 · 网络问答


18. 套接字通信与线上状态排查(热度 193 · 进阶) ​

Q: 服务端大量 TIME_WAIT / CLOSE_WAIT 分别说明什么?怎么排查?

A:

状态含义 ​

TIME_WAIT 多

  • 出现在主动关闭方。
  • 说明该侧在大量主动关闭连接,典型:未开 keep-alive 的 HTTP 服务、反向代理主动断开、短连接客户端/服务端模型。
  • 通常是正常现象,但过多会:
    • 耗尽本地 ephemeral 端口;
    • 占用内存(tcp_max_tw_buckets)。
  • 优化:开启连接池/长连接、net.ipv4.tcp_tw_reuse、调整 ip_local_port_range、tcp_max_tw_buckets;tcp_tw_recycle(NAT 下有坑)自 Linux 4.12 起已删除,本机 /proc/sys/net/ipv4/tcp_tw_recycle 已不存在,新内核上无从调起。

CLOSE_WAIT 多

  • 本端已收到对端 FIN,TCP 栈已进入 CLOSE_WAIT,但应用层迟迟没有调用 close()/shutdown。
  • 典型是代码 bug:
    • 连接未释放;
    • 线程阻塞在读/锁;
    • 异常路径未关闭;
    • 连接池泄漏;
    • 框架/HTTP 客户端未归还连接。
  • 后果:fd 与内存持续增长,最终 too many open files、accept 失败、雪崩。

口诀:

大量 CLOSE_WAIT = 应用没关 socket(代码问题);大量 TIME_WAIT = 主动关闭方短连接多(可优化)。 不看代码也能通过「谁处于 TIME_WAIT」判断谁主动断开。

设计动机 / 深层 ​

  • TCP 状态机由内核维护;应用不调用 close,内核不能擅自把 CLOSE_WAIT 变成 LAST_ACK——必须由应用确认结束。
  • TIME_WAIT 属于主动关闭方的保护性状态(见第 2 题 2MSL),不应视作纯垃圾状态。

常见追问 ​

追问 1:TIME_WAIT 多一定是故障吗?怎么优化?

  • 答题要点: 通常是短连接负载高的正常结果,不是故障本身;故障信号是端口耗尽、性能下降。优化连接复用与 keep-alive,而不是简单清状态。

追问 2:CLOSE_WAIT 的修复方向?

  • 答题要点: 修代码——确保所有出口关闭连接;读完 body 再还池;设置连接/读写超时;监控 fd;对下游慢响应做隔离降级,避免线程占满导致关不掉。

追问 3:还有哪些 TCP 状态值得关注?

  • 答题要点: SYN_RECV 多可能 SYN 队列攻击/半连接堆积;FIN_WAIT_2 异常多可能对端不回 FIN;LAST_ACK 多配合 CLOSE_WAIT 反映关闭流程卡住;ESTABLISHED 暴涨看连接泄漏或流量上涨。

易错点 ​

易错说法纠正
「TIME_WAIT 和 CLOSE_WAIT 都是网络问题」CLOSE_WAIT 多为应用 bug
「CLOSE_WAIT 在主动关闭方」在被动关闭方(收到 FIN 未 close)
「ss/netstat 看不到进程」需权限 -p,且有时需 root
「把 TIME_WAIT 强行清空就没事」可能丢保护、掩盖连接模型问题
「fd 多一定是泄漏」也可能是正常高并发;看增长斜率与是否回收

与选择题对照 ​

  • 主库 150: 第 138 题(大量 CLOSE_WAIT 通常说明)、第 62/63 题(挥手与 TIME_WAIT)、第 136/137 题(ping 连通与网关)、第 38/39 题(ICMP 排障)、第 59 题(端到端)。
  • 补题 16: 补-11(TCP 标志位,FIN/ACK 状态理解)。
  • 口述联动: 选择题直接问 CLOSE_WAIT 含义;面试必须给排查命令与优化,而不是只背定义。

工程 / 抓包背景 ​

  • ss 系列:
    bash
    ss -s
    ss -tanp
    ss -tan state close-wait '( sport = :443 )'
    ss -ti   # rtt/cwnd 等
  • sysctl: tcp_tw_reuse、tcp_max_tw_buckets、net.ipv4.ip_local_port_range、net.core.somaxconn、应用层 backlog。
  • Nginx: worker_connections、keepalive 上游、proxy_ignore_client_abort 等与连接生命周期相关。
  • 排查顺序(口诀化): ss -tan 按状态计数 → ss -tan state close-wait / state time-wait 定位是哪一侧 → ss -tanp / lsof -p <pid> 看 fd 是否单调上涨 → 抓包确认 FIN/ACK 时序(谁先关)→ 查代码 close/连接池归还/超时设置 → 检查 ulimit -n 与 backlog、sysctl。
  • curl 复现: 高并发短连接压测观察 TIME_WAIT 上涨;故意不读响应/中止客户端看服务端状态。
  • Java/Go 常见坑: 响应 body 未 close、连接池 borrow 未 return、HTTP 客户端全局连接数过小导致排队。

持续学习,持续积累。