更新时间:2021-09-09 11:16:45
某用户使用如下命令上传目录到OSS,中间隐去bucket name。
./ossutil cp oss://<xxxx>/img/330802010400071904 -r -j 15 /home/oss/vis-test/
出现如下错误。
由于Linux分配的客户端连接端口用尽,无法建立socket连接所致,虽然socket正常关闭,但是端口不是立即释放,而是处于TIME_WAIT状态,默认等待60s后才释放。
由于客户端频繁的连服务器,由于每次连接都在很短的时间内结束,导致很多的TIME_WAIT,且用光了可用的端口号,所以新的连接没办法绑定端口,即"Cannot assign requested address"
是客户端的问题不是服务器端的问题。
通过netstat,可查看处于TIME_WAIT状态的连接。
sudo sysctl -a | grep tw
sudo netstat -antp | grep TIME_WAIT | wc -l
为什么会出现这种情况?先看下TCP状态图。
TCP的连接有11种状态。
- ESTABLISHED
The socket has an established connection.
- SYN_SENT
The socket is actively attempting to establish a connection.
- SYN_RECV
A connection request has been received from the network.
- FIN_WAIT1
The socket is closed, and the connection is shutting down.
- FIN_WAIT2
Connection is closed, and the socket is waiting for a shutdown from the remote end.
- TIME_WAIT
The socket is waiting after close to handle packets still in the network.
- CLOSE
The socket is not being used.
- CLOSE_WAIT
The remote end has shut down, waiting for the socket to close.
- LAST_ACK
The remote end has shut down, and the socket is closed. Waiting for acknowledgement.
- LISTEN
The socket is listening for incoming connections.
- CLOSING
Both sockets are shut down but we still don't have all our data sent.
通过netstat命令可能还能看到UNKNOWN状态。
- UNKNOWN
The state of the socket is unknown.
TCP规则规定如何基于当前状态及在该状态下所接收的分节从一个状态转换到另一个状态。
比如,
ESTABLISHED状态转移
TIME_WAIT状态又称为2MSL等待状态。
所谓MSL (Maximum Segment Lifetime)指的是报文段在网络内存活的最大时间。RFC 793建议的MSL为2分钟,具体的实现中一般为30秒或1分钟。
TIME_WAIT状态能够
当TCP执行一个主动关闭,并发回最后一个ACK,该连接必须在TIME_WAIT状态停留2MSL时间。
这样可让TCP再次发送最后的ACK以防这个ACK丢失(如果丢失的话,另一端超时并重发最后的FIN)。
假设在192.168.1.254:1500和192.168.11.219:21端口之间有一个TCP连接。关闭这个连接,过一段时间后在相同的
IP:port之间建立另外一个连接。
后一个连接称为前一个连接的化身(incarnation),因为连接的IP:port相同,TCP必须防止某个连接的老的分组在该
连接终止后再现,从而被误解成属于同一个连接的某个新的化身。
为做到这一点,TCP将不给处于TIME_WAIT状态的连接发起新的化身。既然TIME_WAIT状态的持续时间是2MSL,这就足以
让某个方向上的分组最多存活MSL秒即被丢弃,另一个方向上的应答最多存活MSL秒被丢弃。
通过实施这一个规则,就能保证每成功建立一个TCP连接时,来自该连接先前化身的老的重复分组都已经在网络中消逝了。
修改运行ossutil 所在机器上的系统tcp参数。
- 调低端口释放后的等待时间,默认为60s,修改为30s或者15s
sysctl -w net.ipv4.tcp_fin_timeout=30
- tcp_tw_resue, 默认为0,修改为1,释放TIME_WAIT端口给新连接使用
sysctl -w net.ipv4.tcp_tw_reuse=1
- 支持TCP时间戳
sysctl -w net.ipv4.tcp_timestamps=1
- 快速回收socket资源,默认为0,修改为1
sysctl -w net.ipv4.tcp_tw_recycle=1
- 持久化
sysctl -p
$ sysctl -a |grep port_range
net.ipv4.ip_local_port_range = 52768 60999 ====>52768~60999端口可用
修改该参数
$ vi /etc/sysctl.conf
net.ipv4.ip_local_port_range = 22768 60999 ====>22768~60999端口可用