Linux中TCP三次握手与四次挥手介绍及调优

系统 Linux
TCP是一种面向连接的单播协议,在发送数据前,通信双方必须在彼此间建立一条连接。所谓的“连接”,其实是客户端和服务器的内存里保存的一份关于对方的信息,如ip地址、端口号等。

[[415215]]

TCP介绍

TCP是一种面向连接的单播协议,在发送数据前,通信双方必须在彼此间建立一条连接。所谓的“连接”,其实是客户端和服务器的内存里保存的一份关于对方的信息,如ip地址、端口号等。

TCP可以看成是一种字节流,它会处理IP层或以下的层的丢包、重复以及错误问题。在连接的建立过程中,双方需要交换一些连接的参数。这些参数可以放在TCP头部。

TCP提供了一种可靠、面向连接、字节流、传输层的服务,采用三次握手建立一个连接。采用4次挥手来关闭一个连接。

TCP三次握手

客户端和服务端通信前要进行连接,“3次握手”的作用就是双方都能明确自己和对方的收、发能力是正常的。

  • 第一次握手:客户端发送网络包,服务端收到了。这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
  • 第二次握手:服务端发包,客户端收到了。这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。从客户端的视角来看,我接到了服务端发送过来的响应数据包,说明服务端接收到了我在第一次握手时发送的网络包,并且成功发送了响应数据包,这就说明,服务端的接收、发送能力正常。而另一方面,我收到了服务端的响应数据包,说明我第一次发送的网络包成功到达服务端,这样,我自己的发送和接收能力也是正常的。
  • 第三次握手:客户端发包,服务端收到了。这样服务端就能得出结论:客户端的接收、发送能力,服务端的发送、接收能力是正常的。第一、二次握手后,服务端并不知道客户端的接收能力以及自己的发送能力是否正常。而在第三次握手时,服务端收到了客户端对第二次握手作的回应。从服务端的角度,我在第二次握手时的响应数据发送出去了,客户端接收到了。所以,我的发送能力是正常的。而客户端的接收能力也是正常的。

经历了上面的三次握手过程,客户端和服务端都确认了自己的接收、发送能力是正常的。之后就可以正常通信了。

TCP三次握手中的状态

在 TCP 三次握手的时候,Linux 内核会维护两个队列,分别是:

  • 半连接队列,也称 SYN 队列;
  • 全连接队列,也称 accepet 队列;

服务端收到客户端发起的 SYN 请求后,内核会把该连接存储到半连接队列,并向客户端响应 SYN+ACK,接着客户端会返回 ACK,服务端收到第三次握手的 ACK 后,内核会把连接从半连接队列移除,然后创建新的完全的连接,并将其添加到 accept 队列,等待进程调用 accept 函数时把连接取出来。

不管是半连接队列还是全连接队列,都有最大长度限制,超过限制时,内核会直接丢弃,或返回 RST 包。

半连接

很遗憾,我们没有命令可以查看系统的半连接队列数量。但是我们可以抓住 TCP 半连接的特点,就是服务端处于 SYN_RECV 状态的 TCP 连接,就是 TCP 半连接队列。使用如下命令计算当前 TCP 半连接队列长度:

  1. $ netstat |grep SYN_RECV |wc -l 
  2. 1723 

SYN_RECV 状态下,服务器必须建立一个 SYN 半连接队列来维护未完成的握手信息,当这个队列溢出后,服务器将无法再建立新连接。

如何模拟 TCP 半连接队列溢出场景?

模拟 TCP 半连接溢出场景不难,实际上就是对服务端一直发送 TCP SYN 包,但是不回第三次握手 ACK,这样就会使得服务端有大量的处于 SYN_RECV 状态的 TCP 连接。这其实也就是所谓的 SYN 洪泛、SYN 攻击、DDos 攻击。

图片

实验环境:

  • 客户端和服务端都是 CentOS Linux release 7.9.2009 (Core) ,Linux 内核版本 3.10.0-1160.15.2.el7.x86_64
  • 服务端 IP 172.16.0.20,客户端 IP 172.16.0.157
  • 服务端是 Nginx 服务,端口为 80

本次实验使用 hping3 工具模拟 SYN 攻击:

  1. $ hping3 -S -p 80 --flood 172.16.0.20 
  2. HPING 172.16.0.20 (eth0 172.16.0.20): S set, 40 headers + 0 data bytes 
  3. hping in flood mode, no replies will be shown 

新连接建立失败的原因有很多,怎样获得由于队列已满而引发的失败次数呢?netstat -s 命令给出的统计结果中可以得到。

  1. $ netstat -s|grep "SYNs to LISTEN" 
  2.     1541918 SYNs to LISTEN sockets dropped 

这里给出的是队列溢出导致 SYN 被丢弃的个数。注意这是一个累计值,如果数值在持续增加,则应该调大 SYN 半连接队列。修改队列大小的方法,是设置 Linux 的 tcp_max_syn_backlog 参数:

  1. sysctl -w net.ipv4.tcp_max_syn_backlog = 1024 

如果 SYN 半连接队列已满,只能丢弃连接吗?并不是这样,开启 syncookies 功能就可以在不使用 SYN 队列的情况下成功建立连接。syncookies 是这么做的:服务器根据当前状态计算出一个值,放在己方发出的 SYN+ACK 报文中发出,当客户端返回 ACK 报文时,取出该值验证,如果合法,就认为连接建立成功,如下图所示。

Linux 下怎样开启 syncookies 功能呢?修改 tcp_syncookies 参数即可,其中值为 0 时表示关闭该功能,2 表示无条件开启功能,而 1 则表示仅当 SYN 半连接队列放不下时,再启用它。由于 syncookie 仅用于应对 SYN 泛洪攻击(攻击者恶意构造大量的 SYN 报文发送给服务器,造成 SYN 半连接队列溢出,导致正常客户端的连接无法建立),这种方式建立的连接,许多 TCP 特性都无法使用。所以,应当把 tcp_syncookies 设置为 1,仅在队列满时再启用。

  1. sysctl -w net.ipv4.tcp_syncookies = 1 

全连接

在服务端可以使用 ss 命令,来查看 TCP 全连接队列的情况:但需要注意的是 ss 命令获取的 Recv-Q/Send-Q 在「LISTEN 状态」和「非 LISTEN 状态」所表达的含义是不同的。从下面的内核代码可以看出区别:

  1. static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, 
  2.          void *_info) 
  3.  const struct tcp_sock *tp = tcp_sk(sk); 
  4.  struct tcp_info *info = _info; 
  5.  
  6.  if (sk->sk_state == TCP_LISTEN) { 
  7.   r->idiag_rqueue = sk->sk_ack_backlog; 
  8.   r->idiag_wqueue = sk->sk_max_ack_backlog; 
  9.  } else { 
  10.   r->idiag_rqueue = tp->rcv_nxt - tp->copied_seq; 
  11.   r->idiag_wqueue = tp->write_seq - tp->snd_una; 
  12.  } 
  13.  if (info != NULL
  14.   tcp_get_info(sk, info); 

在「LISTEN 状态」时,Recv-Q/Send-Q 表示的含义如下:

  1. $ ss -ltnp 
  2. LISTEN     0      1024         *:8081                     *:*                   users:(("java",pid=5686,fd=310)) 
  • Recv-Q:当前全连接队列的大小,也就是当前已完成三次握手并等待服务端 accept() 的 TCP 连接;
  • Send-Q:当前全连接最大队列长度,上面的输出结果说明监听 8088 端口的 TCP 服务,最大全连接长度为 1024;

在「非 LISTEN 状态」时,Recv-Q/Send-Q 表示的含义如下:

  1. $ ss -tnp 
  2. ESTAB      0      0      172.16.0.20:57672              172.16.0.20:2181                users:(("java",pid=5686,fd=292)) 
  • Recv-Q:已收到但未被应用进程读取的字节数;
  • Send-Q:已发送但未收到确认的字节数;

如何模拟 TCP 全连接队列溢出的场景?

实验环境:

  • 客户端和服务端都是 CentOS Linux release 7.9.2009 (Core) ,Linux 内核版本 3.10.0-1160.15.2.el7.x86_64
  • 服务端 IP 172.16.0.20,客户端 IP 172.16.0.157
  • 服务端是 Nginx 服务,端口为 80

ab是apache bench命令的缩写。ab是apache自带的压力测试工具。ab非常实用,它不仅可以对apache服务器进行网站访问压力测试,也可以对或其它类型的服务器进行压力测试。比如nginx、tomcat、IIS等。ab的原理:ab命令会创建多个并发访问线程,模拟多个访问者同时对某一URL地址进行访问。它的测试目标是基于URL的,因此,它既可以用来测试apache的负载压力,也可以测试nginx、lighthttp、tomcat、IIS等其它Web服务器的压力。ab命令对发出负载的计算机要求很低,它既不会占用很高CPU,也不会占用很多内存。但却会给目标服务器造成巨大的负载,其原理类似CC攻击。自己测试使用也需要注意,否则一次上太多的负载。可能造成目标服务器资源耗完,严重时甚至导致死机。

TCP 全连接队列的最大值取决于 somaxconn 和 backlog 之间的最小值,也就是 min(somaxconn, backlog)。从下面的 Linux 内核代码可以得知:

  1. int __sys_listen(int fd, int backlog) 
  2.  struct socket *sock; 
  3.  int err, fput_needed; 
  4.  int somaxconn; 
  5.  
  6.  sock = sockfd_lookup_light(fd, &err, &fput_needed); 
  7.  if (sock) { 
  8.   somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn; 
  9.   if ((unsigned int)backlog > somaxconn) 
  10.    backlog = somaxconn; 
  11.  
  12.   err = security_socket_listen(sock, backlog); 
  13.   if (!err) 
  14.    err = sock->ops->listen(sock, backlog); 
  15.  
  16.   fput_light(sock->file, fput_needed); 
  17.  } 
  18.  return err; 
  • somaxconn 是 Linux 内核的参数,默认值是 128,可以通过 /proc/sys/net/core/somaxconn 来设置其值;我们设置为40000了。
  • backlog 是 listen(int sockfd, int backlog) 函数中的 backlog 大小,Nginx 默认值是 511,可以通过修改配置文件设置其长度;

所以测试环境的 TCP 全连接队列最大值为 min(128, 511),也就是 511,可以执行 ss 命令查看:

  1. ss -tulnp|grep 80 
  2. tcp    LISTEN     0      511       *:80                    *:*                   users:(("nginx",pid=22913,fd=6),("nginx",pid=22912,fd=6),("nginx",pid=22911,fd=6))         
  3. tcp    LISTEN     0      511    [::]:80                 [::]:*                   users:(("nginx",pid=22913,fd=7),("nginx",pid=22912,fd=7),("nginx",pid=22911,fd=7)) 

客户端执行 ab 命令对服务端发起压力测试,并发 1 万个连接,发送10万个包:

  1. -n表示总的请求数为10000 
  2. -c表示并发请求数为1000 
  3. ab -c 10000 -n 100000 http://172.16.0.20:80/ 
  4. This is ApacheBench, Version 2.3 <$Revision: 1430300 $> 
  5. Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ 
  6. Licensed to The Apache Software Foundation, http://www.apache.org/ 
  7.  
  8. Benchmarking 172.16.0.20 (be patient) 
  9. Completed 10000 requests 
  10. Completed 20000 requests 
  11. Completed 30000 requests 
  12. Completed 40000 requests 
  13. Completed 50000 requests 
  14. Completed 60000 requests 
  15. Completed 70000 requests 
  16. Completed 80000 requests 
  17. Completed 90000 requests 
  18. Completed 100000 requests 
  19. Finished 100000 requests 
  20.  
  21.  
  22. Server Software:        nginx/1.20.1 
  23. Server Hostname:       172.16.0.20 
  24. Server Port:            80 
  25.  
  26. Document Path:          / 
  27. Document Length:        4833 bytes 
  28.  
  29. Concurrency Level:      10000 
  30. Time taken for tests:   2.698 seconds 
  31. Complete requests:      100000 
  32. Failed requests:        167336 
  33.    (Connect: 0, Receive: 0, Length: 84384, Exceptions: 82952) 
  34. Write errors:           0 
  35. Total transferred:      86399264 bytes 
  36. HTML transferred:       82392984 bytes 
  37. Requests per second:    37069.19 [#/sec] (mean) 
  38. Time per request:       269.766 [ms] (mean) 
  39. Time per request:       0.027 [ms] (mean, across all concurrent requests) 
  40. Transfer rate:          31276.86 [Kbytes/sec] received 
  41.  
  42. Connection Times (ms) 
  43.               min  mean[+/-sd] median   max 
  44. Connect:        0  129 151.5    106    1144 
  45. Processing:    39  121  37.7    114     239 
  46. Waiting:        0   23  51.8      0     159 
  47. Total:        142  250 152.4    224    1346 
  48.  
  49. Percentage of the requests served within a certain time (ms) 
  50.   50%    224 
  51.   66%    227 
  52.   75%    232 
  53.   80%    236 
  54.   90%    283 
  55.   95%    299 
  56.   98%   1216 
  57.   99%   1228 
  58.  100%   1346 (longest request) 

其间共执行了两次 ss 命令,从上面的输出结果,可以发现当前 TCP 全连接队列上升到了 512 大小,超过了最大 TCP 全连接队列。

  1.  ss -tulnp|grep 80 
  2. tcp    LISTEN     411    511       *:80                    *:*                   users:(("nginx",pid=22913,fd=6),("nginx",pid=22912,fd=6),("nginx",pid=22911,fd=6)) 
  3. ss -tulnp|grep 80 
  4. tcp    LISTEN     512    511       *:80                    *:*                   users:(("nginx",pid=22913,fd=6),("nginx",pid=22912,fd=6),("nginx",pid=22911,fd=6)) 

当超过了 TCP 最大全连接队列,服务端则会丢掉后续进来的 TCP 连接,丢掉的 TCP 连接的个数会被统计起来,我们可以使用 netstat -s 命令来查看:

  1. netstat -s|grep overflowed 
  2.    1233972 times the listen queue of a socket overflowed 

上面看到的 1233972 times ,表示全连接队列溢出的次数,注意这个是累计值。可以隔几秒钟执行下,如果这个数字一直在增加的话肯定全连接队列满了。

  1. netstat -s|grep overflowed 
  2.     1292022 times the listen queue of a socket overflowed 

从上面的模拟结果,可以得知,当服务端并发处理大量请求时,如果 TCP 全连接队列过小,就容易溢出。发生 TCP 全连接队列溢出的时候,后续的请求就会被丢弃,这样就会出现服务端请求数量上不去的现象。

Linux 有个参数可以指定当 TCP 全连接队列满了会使用什么策略来回应客户端

实际上,丢弃连接只是 Linux 的默认行为,我们还可以选择向客户端发送 RST 复位报文,告诉客户端连接已经建立失败。

  1. $ cat /proc/sys/net/ipv4/tcp_abort_on_overflow 

tcp_abort_on_overflow 共有两个值分别是 0 和 1,其分别表示:

  • 0 :如果全连接队列满了,那么 server 扔掉 client 发过来的 ack ;
  • 1 :如果全连接队列满了,server 发送一个 reset 包给 client,表示废掉这个握手过程和这个连接;

如果要想知道客户端连接不上服务端,是不是服务端 TCP 全连接队列满的原因,那么可以把 tcp_abort_on_overflow 设置为 1,这时如果在客户端异常中可以看到很多 connection reset by peer 的错误,那么就可以证明是由于服务端 TCP 全连接队列溢出的问题。通常情况下,应当把 tcp_abort_on_overflow 设置为 0,因为这样更有利于应对突发流量。所以,tcp_abort_on_overflow 设为 0 可以提高连接建立的成功率,只有你非常肯定 TCP 全连接队列会长期溢出时,才能设置为 1 以尽快通知客户端。

  1. sysctl -w net.ipv4.tcp_abort_on_overflow = 0 

如何增大 TCP 全连接队列呢?

根据上面提到的TCP 全连接队列的最大值取决于 somaxconn 和 backlog 之间的最小值,也就是 min(somaxconn, backlog)。我们现在调整somaxconn值:

  1. $ sysctl -w net.core.somaxconn=65535 

调整nginx配置:

  1. server { 
  2.     listen  80  backlog=65535; 
  3.     ... 

最后要重启 Nginx 服务,因为只有重新调用 listen() 函数 TCP 全连接队列才会重新初始化。服务端执行 ss 命令,查看 TCP 全连接队列大小:

  1. $ ss -tulntp|grep 80 
  2. tcp    LISTEN     0       65535    *:80                    *:*                   users:(("nginx",pid=24212,fd=6),("nginx",pid=24211,fd=6),("nginx",pid=24210,fd=6)) 

从执行结果,可以发现 TCP 全连接最大值为 65535。

增大 TCP 全连接队列后,继续压测

  1. ab -c 10000 -n 100000 http://172.16.0.20:80/ 
  2. This is ApacheBench, Version 2.3 <$Revision: 1430300 $> 
  3. Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ 
  4. Licensed to The Apache Software Foundation, http://www.apache.org/ 
  5.  
  6. Benchmarking 172.16.0.20 (be patient) 
  7. Completed 10000 requests 
  8. Completed 20000 requests 
  9. Completed 30000 requests 
  10. Completed 40000 requests 
  11. Completed 50000 requests 
  12. Completed 60000 requests 
  13. Completed 70000 requests 
  14. Completed 80000 requests 
  15. Completed 90000 requests 
  16. Completed 100000 requests 
  17. Finished 100000 requests 
  18.  
  19.  
  20. Server Software:        nginx/1.20.1 
  21. Server Hostname:        172.16.0.20 
  22. Server Port:            80 
  23.  
  24. Document Path:          / 
  25. Document Length:        4833 bytes 
  26.  
  27. Concurrency Level:      10000 
  28. Time taken for tests:   2.844 seconds 
  29. Complete requests:      100000 
  30. Failed requests:        178364 
  31.    (Connect: 0, Receive: 0, Length: 89728, Exceptions: 88636) 
  32. Write errors:           0 
  33. Total transferred:      57592752 bytes 
  34. HTML transferred:       54922212 bytes 
  35. Requests per second:    35159.35 [#/sec] (mean) 
  36. Time per request:       284.419 [ms] (mean) 
  37. Time per request:       0.028 [ms] (mean, across all concurrent requests) 
  38. Transfer rate:          19774.64 [Kbytes/sec] received 
  39.  
  40. Connection Times (ms) 
  41.               min  mean[+/-sd] median   max 
  42. Connect:        0  130  18.3    130     172 
  43. Processing:    45  142  40.1    138     281 
  44. Waiting:        0   19  52.4      0     185 
  45. Total:        159  272  31.2    272     390 
  46.  
  47. Percentage of the requests served within a certain time (ms) 
  48.   50%    272 
  49.   66%    274 
  50.   75%    275 
  51.   80%    276 
  52.   90%    280 
  53.   95%    358 
  54.   98%    370 
  55.   99%    375 
  56.  100%    390 (longest request) 

服务端执行 ss 命令,查看 TCP 全连接队列使用情况:

  1. $ ss -tulnp|grep 80 
  2. tcp    LISTEN     8      65535     *:80                    *:*                   users:(("nginx",pid=24212,fd=6),("nginx",pid=24211,fd=6),("nginx",pid=24210,fd=6)) 
  3. $ ss -tulnp|grep 80 
  4. tcp    LISTEN     352    65535     *:80                    *:*                   users:(("nginx",pid=24212,fd=6),("nginx",pid=24211,fd=6),("nginx",pid=24210,fd=6)) 
  5. $ ss -tulnp|grep 80 
  6. tcp    LISTEN     0      65535     *:80                    *:*                   users:(("nginx",pid=24212,fd=6),("nginx",pid=24211,fd=6),("nginx",pid=24210,fd=6)) 

从上面的执行结果,可以发现全连接队列使用增长的很快,但是一直都没有超过最大值,所以就不会溢出,那么 netstat -s 就不会有 TCP 全连接队列溢出个数继续增加:

  1. $ netstat -s|grep overflowed 
  2.     1540879 times the listen queue of a socket overflowed 
  3. $ netstat -s|grep overflowed 
  4.     1540879 times the listen queue of a socket overflowed 
  5. $ netstat -s|grep overflowed 
  6.     1540879 times the listen queue of a socket overflowed 
  7. $ netstat -s|grep overflowed 
  8.     1540879 times the listen queue of a socket overflowed 

说明 TCP 全连接队列最大值从 512 增大到 65535 后,服务端抗住了 10 万连接并发请求,也没有发生全连接队列溢出的现象了。如果持续不断地有连接因为 TCP 全连接队列溢出被丢弃,就应该调大 backlog 以及 somaxconn 参数。

TCP四次挥手

  • 第一次挥手:主动关闭方发送一个FIN,用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方:我已经不会再给你发数据了(当然,在fin包之前发送出去的数据,如果没有收到对应的ack确认报文,主动关闭方依然会重发这些数据),但此时主动关闭方还可以接受数据。
  • 第二次挥手:被动关闭方收到FIN包后,发送一个ACK给对方,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号)。
  • 第三次挥手:被动关闭方发送一个FIN,用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会再给你发数据了。
  • 第四次挥手:主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手。

互联网中往往服务器才是主动关闭连接的一方。这是因为,HTTP 消息是单向传输协议,服务器接收完请求才能生成响应,发送完响应后就会立刻关闭 TCP 连接,这样及时释放了资源,能够为更多的用户服务。

四次挥手的状态

我们来看断开连接的时候的状态时序图:

其实四次挥手只涉及两种报文:FIN 和 ACK。FIN 就是 Finish 结束连接的意思,谁发出 FIN 报文,就表示它将不再发送任何数据,关闭这一方向的传输通道。ACK 是 Acknowledge 确认的意思,它用来通知对方,你方的发送通道已经关闭。

  • 当主动方关闭连接时,会发送 FIN 报文,此时主动方的连接状态由 ESTABLISHED 变为 FIN_WAIT1。
  • 当被动方收到 FIN 报文后,内核自动回复 ACK 报文,连接状态由 ESTABLISHED 变为 CLOSE_WAIT,顾名思义,它在等待进程调用 close 函数关闭连接。
  • 当主动方接收到这个 ACK 报文后,连接状态由 FIN_WAIT1 变为 FIN_WAIT2,主动方的发送通道就关闭了。
  • 当被动方进入 CLOSE_WAIT 状态时,进程的 read 函数会返回 0,这样开发人员就会有针对性地调用 close 函数,进而触发内核发送 FIN 报文,此时被动方连接的状态变为 LAST_ACK。当主动方收到这个 FIN 报文时,内核会自动回复 ACK,同时连接的状态由 FIN_WAIT2 变为 TIME_WAIT,Linux 系统下等待的时间设为 2MSL,MSL 是 Maximum Segment Lifetime,报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。TIME_WAIT 状态的连接才会彻底关闭。

当被动方收到 ACK 报文后,连接就会关闭。

主动方TIME_WAIT优化

大量处于 TIME_WAIT 状态的连接,它们会占用大量内存和端口资源。这时,我们可以优化与 TIME_WAIT 状态相关的内核选项,比如采取下面几种措施。

  • 增大处于 TIME_WAIT 状态的连接数量 net.ipv4.tcp_max_tw_buckets ,并增大连接跟踪表的大小 net.netfilter.nf_conntrack_max。
  1. sysctl -w net.ipv4.tcp_max_tw_buckets=1048576 
  2. sysctl -w net.netfilter.nf_conntrack_max=1048576 
  • 减小FIN_WAIT2状态的参数 net.ipv4.tcp_fin_timeout 的时间和减小TIME_WAIT 状态的参数net.netfilter.nf_conntrack_tcp_timeout_time_wait的时间 ,让系统尽快释放它们所占用的资源。
  1. sysctl -w net.ipv4.tcp_fin_timeout=15 
  2. sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30 
  • 开启端口复用 net.ipv4.tcp_tw_reuse。这样,被 TIME_WAIT 状态占用的端口,还能用到新建的连接中。
  1. sysctl -w net.ipv4.tcp_tw_reuse=1 
  • 增大本地端口的范围 net.ipv4.ip_local_port_range 。这样就可以支持更多连接,提高整体的并发能力。
  1. sysctl -w net.ipv4.ip_local_port_range="1024 65535" 
  • 增加最大文件描述符的数量。你可以使用 fs.nr_open 和 fs.file-max ,分别增大进程和系统的最大文件描述符数;或在应用程序的 systemd 配置文件中,配置 LimitNOFILE ,设置应用程序的最大文件描述符数。
  1. sysctl -w fs.nr_open=1048576 
  2. sysctl -w fs.file-max=1048576 

巨人的肩膀

[1] 系统性能调优必知必会.陶辉.极客时间.

[2] TCP/IP详解卷二:实现

本文转载自微信公众号「 运维开发故事」,可以通过以下二维码关注。转载本文请联系 运维开发故事公众号。

【编辑推荐】

【责任编辑:姜华 TEL:(010)68476606】
责任编辑:姜华 来源: 运维开发故事
相关推荐

2024-01-12 08:23:11

TCPACK服务器

2019-06-12 11:26:37

TCP三次握手四次挥手

2015-10-13 09:42:52

TCP网络协议

2023-10-24 15:22:09

TCPUDP

2020-02-17 10:10:43

TCP三次握手四次挥手

2021-07-03 17:47:25

TCP控制协议

2021-01-29 06:11:08

TCP通信三次握手

2021-05-18 12:27:40

TCP控制协议

2019-02-01 09:38:16

2015-11-09 09:58:56

2014-09-19 09:46:46

TCPIP

2017-09-25 21:27:07

TCP协议数据链

2021-05-28 09:08:20

TCP连接序列号

2020-06-29 14:50:47

TCP状态ACK

2023-10-28 09:07:57

TCP面试三次握手

2022-11-17 10:20:49

TCP三次握手四次挥手

2020-03-02 14:41:04

运维架构技术

2023-11-01 08:04:08

WiresharkTCP协议

2023-10-17 15:44:19

TCP四次挥手

2020-01-09 09:31:05

三次握手四次挥手 TCP
点赞
收藏

51CTO技术栈公众号