在高并发短连接场景中,TCP 连接的频繁建立与释放可能导致系统出现连接耗尽或连接建立失败的问题。
背景
在现代互联网应用中,高并发短连接场景极其常见,如 HTTP 服务器、RPC 调用等。这些场景的特点是单个客户端或服务器会在短时间内建立和关闭大量 TCP 连接,例如:
- Web 应用服务器:每秒可能处理数千次来自不同客户端的 HTTP 请求,每个请求结束后连接即被关闭。
- 消息队列系统:生产者和消费者之间频繁地发送和接收消息,每次通信可能只维持很短的连接时间。
虽然短连接可以有效释放资源,但如果连接的建立和释放过于频繁,可能会导致以下问题:
- 动态端口耗尽:操作系统为每个新连接分配一个动态端口(通常范围是 49152 到 65535),当高并发时,可能会出现端口数量不足的情况,从而无法建立新的连接。
- TIME_WAIT 连接堆积:TCP 连接在关闭后会进入 TIME_WAIT 状态,该状态默认持续时间为 2MSL(Maximum Segment Lifetime),通常为几分钟。如果短时间内有大量连接进入 TIME_WAIT 状态,会占用大量的系统端口资源,进一步加剧端口耗尽问题。
解决方案
1. 调整 TCP 动态端口范围
工作原理
操作系统为每个新连接分配一个动态端口(通常范围是 49152 到 65535),当高并发时,可能会出现端口数量不足的情况。通过扩大动态端口范围,可以增加可用端口数量,从而在高并发时降低端口耗尽的风险。
具体操作
Windows
查看范围命令:
1
2netsh int ipv4 show dynamicport tcp
netsh int ipv6 show dynamicport tcp调整范围命令:
1
2netsh int ipv4 set dynamicport tcp start=1024 num=64511
netsh int ipv6 set dynamicport tcp start=1024 num=64511扩大动态端口范围为 1024-65535(共 64512 个端口)。
Linux
查看范围命令:
1
2sysctl net.ipv4.ip_local_port_range
ss -Hlnt调整范围命令:
1
2
3sysctl -w net.ipv4.ip_local_port_range="1024 65535"
echo "net.ipv4.ip_local_port_range = 1024 65535" >> /etc/sysctl.conf
sysctl -p将动态端口范围调整为 1024-65535。
macOS
查看范围命令:
1
2sysctl net.inet.ip.portrange
netstat -anp tcp | grep ESTABLISHED调整范围命令:
1
2sysctl -w net.inet.ip.portrange.first=1024
sysctl -w net.inet.ip.portrange.last=65535修改动态端口范围为 1024-65535。
注意事项
- 扩大动态端口范围可以推迟端口耗尽的发生,但端口数量是有限的(受限于系统资源和网络限制)。因此,动态端口范围的调整应结合系统的实际需求和能力。
- 在调整动态端口范围时,应确保新的范围不与系统中其他应用(如系统服务、数据库等)使用的固定端口冲突。
2. 优化 TIME_WAIT 时间限制
工作原理
TIME_WAIT 状态是 TCP 连接关闭过程中的一个必要步骤,该状态默认持续时间为 2MSL(Maximum Segment Lifetime),通常为几分钟。如果短时间内有大量连接进入 TIME_WAIT 状态,会占用大量的系统端口资源,进一步加剧端口耗尽问题。通过缩短 TIME_WAIT 时间或启用更快的端口回收机制,可以加速端口资源的释放。
具体操作
Windows
查看当前 TIME_WAIT 状态命令:
1
netstat -ano | findstr "TIME_WAIT"
调整 TIME_WAIT 时间设置:
修改注册表中的TcpTimedWaitDelay
参数:打开注册表编辑器,导航到:
1
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
将
TcpTimedWaitDelay
设置为 30(秒)。
Linux
查看当前 TIME_WAIT 状态命令:
1
2netstat -tnpa | grep 'TIME_WAIT'
ss -tnpa | grep 'TIME_WAIT'调整 TIME_WAIT 时间设置:
修改内核参数:1
2
3sysctl -w net.ipv4.tcp_fin_timeout=30
echo "net.ipv4.tcp_fin_timeout = 30" >> /etc/sysctl.conf
sysctl -p
macOS
查看当前 TIME_WAIT 状态命令:
1
netstat -tnpa | grep 'TIME_WAIT'
调整 TIME_WAIT 时间设置:
编辑/etc/sysctl.conf
文件,添加:1
net.inet.tcp.fintimeout=30
并运行:
1
sysctl -p
其他优化措施
启用 TIME_WAIT 重用:在 Linux 中启用 TCP 回收机制:
1
sudo sysctl -w net.ipv4.tcp_tw_reuse=1
启用 TIME_WAIT 快速回收:
1
sudo sysctl -w net.ipv4.tcp_tw_recycle=1
调整最大 TIME_WAIT 套接字数量:
1
sudo sysctl -w net.ipv4.tcp_max_tw_buckets=4096
注意事项
- 调整 TIME_WAIT 时间可能会对网络的稳定性产生一定影响。缩短 TIME_WAIT 时间可能导致一些旧的数据包在网络上重新出现并被处理,从而导致数据传输错误。因此,在调整 TIME_WAIT 时间时应谨慎,并根据实际网络环境和业务需求进行测试。
- 不同操作系统的 TIME_WAIT 时间调整机制不同,请根据具体系统进行相应操作。
- 如果系统中存在大量的 TIME_WAIT 连接,除了调整 TIME_WAIT 时间外,还可以考虑优化应用逻辑,减少不必要的短连接,或者使用连接池技术来复用连接,从而降低连接创建和销毁的频率。
Windows
系统使用powershell
获取当前协议 tcp 动态端口范围和当前 TIME_WAIT 端口数量
1 | $ErrorActionPreference = 'Stop' |