• close_wait相关


    1. CLOSE_WAIT是什么

    TCP关闭时

    • 主动关闭: 发FIN(FIN_WAIT_1) --> 收ACK(FIN_WAIT_2) --> 收FIN(TIME_WAIT) --> 发ACK, TIME_WAIT会持续 2*MSL(1-4分钟)
    • 被动关闭: 收FIN(CLOSE_WAIT) --> 发ACK --> 发FIN(LAST_ACK) --> 收ACK(CLOSED), 如果程序不主动调用 close(fd) 关闭套接字,就不会主动发送FIN,就会一直在 CLOSE_WAIT 状态

    所以 CLOSE_WAIT 存在于被动关闭连接的情况,一般是服务器被动关闭,所以一般需要服务器去解决。

    2. 产生的原因

    主要有两点:

    1. 代码中没有写关闭连接的代码,存在bug;
    2. 该连接的业务代码处理事件太长,代码还在处理,对方已经发起断开连接的请求了;这时候会存在一段时间的 CLOS_WAIT,直到服务端处理到这里。

    总的来说,就是服务端没有及时调用close()关闭套接字。

    3. 一直不关闭,最多会存在多长时间

    内核会定时探测TCP连接是否存在,如果不存在,会自动关闭该TCP,回收系统资源。内核依靠如下参数来探测:

    • tcp_keepalive_time(7200): 如果在该参数指定的秒数内,TCP连接一直处于空闲,内核就开始向对端发起探测,看对端是否还在;
    • tcp_keepalive_intvl(75): 发起探测时,每隔这么多秒数,探测一次;
    • tcp_keepalive_probes(9): 总共探测这么多次;

    所以 CLOSE_WAIT 状态最多维持 tcp_keepalive_time + tcp_keepalive_intvl * tcp_keepalive_probes = 7200 +75*9 = 7875s,约130分钟,2小时多一点。

    这只是内核的限制,还可以在程序里使用 setsocketopt(fd, SOL_TCP, TCP_KEEPIDLE...) 对每个TCP连接设置。

    4. 有什么影响

    CLOSE_WAIT状态的端口表示正在被占用,如果没有设置端口复用,这个端口就变得不可用,过多的CLOSE_WAIT会耗尽系统的可用端口,新的连接进不来,服务变得不可用。

    5. 如何解决

    1. 程序方面,需要及时处理连接被动关闭的状态,特别是 recv() 收到0字节,表示对端关闭了;
    2. 系统方面,可以将 keepalive 相关的参数设置的小一些,让系统尽快探测到TCP不可用,尽快回收资源。

    6. 主动关闭时的两个较长的等待时间

    • FIN_WAIT_2: 等待对端发送 FIN
    • TIME_WAIT: 等待2MSL

    调用了shutdown(),但是没有调用close(),就会等在FIN_WAIT_2状态。跟这个状态有关的内核参数是:

    • net.ipv4.tcp_fin_timeout(30): 注意,这个参数只对调用了close()的孤儿tcp有效,如果程序只是调用了shutdown(),但是没有close(),该参数并不起作用。

    一般主动关闭连接的一方较常见 TIME_WAIT,产生的原因是主动关闭的时候,要等着对端收到了最后一个ACK才回收相应资源,防止对端没有收到ACK又重新发送最后一个FIN。但这也是占用了一个端口,跟这个状态有关的参数是:

    • net.ipv4.tcp_max_tw_buckets(180000): TIME_WAIT的最大数量,超过这个会被立刻清理,并打印警告信息
    • net.ipv4.tcp_tw_timeout(60): TIME_WAIT的过期时间
    • net.ipv4.tcp_tw_reuse(0): TIME_WAIT状态重用
    • net.ipv4.tcp_recycle(0): 开启 TIME_WAT 快速回收。不再是2MSL,而是一个RTO(动态计算的数据包重传超时时间)。还需要tcp_timestamps保证旧连接的数据包不会被新连接接收。NAT环境可能导致drop掉SYN包,无法发起新的连接;
    • net.ipv4.tcp_timestamps(1): 检查请求数据包的时间戳,快速回收需要配合这个时间戳选项;

    7. net.ipv4.tcp_timestamps=1和net.ipv4.tcp_recycle=1在NAT环境下的影响

    简单来说就是NAT会修改目的IP,但有的不修改tcp头里的timestamp,导致不同的客户端通过NAT过来的数据包时间戳不一样,时间戳小的就接不进server,所以server一般不开启 net.ipv4.tcp_recycle。

  • 相关阅读:
    泰国行记三:PP岛三天的休闲时光
    泰国行记二:普吉印象
    177. Nth Highest Salary
    176. Second Highest Salary
    175. Combine Two Tables
    Regular Expression Matching
    斐波那契数列
    用两个栈实现队列
    二叉树的下一个节点
    重建二叉树
  • 原文地址:https://www.cnblogs.com/suntus/p/15468463.html
Copyright © 2020-2023  润新知