news 2026/10/22 7:49:08

JMeter压测报错地址已被占用?端口耗尽排查与解决全攻略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JMeter压测报错地址已被占用?端口耗尽排查与解决全攻略

“address already in use”在JMeter里出现频率极高,基本每个做过压力测试的人都见过。第一次遇到时我刚入门,看着红色报错懵了半天,以为是目标服务挂了,后来排查了一圈,发现锅不在服务端,而在压测机自己身上。这个报错翻成大白话就是:发压的机器上可用端口不够了。这篇就把我从原理到解决踩过的坑一次性说清楚,无论你是刚开始用JMeter的新手,还是被这个报错折磨过的老打工人,照着做基本都能解决。

1. 先搞清楚报错到底是谁发出的

1.1 四次挥手和TIME_WAIT是怎么把端口“锁死”的

TCP连接建立时,客户端会随机占用一个本地端口,比如你用JMeter去请求目标服务的8080端口,JMeter这台机器的TCP层就会在动态端口池里挑一个端口,比如52018,作为这次连接的“发件地址”。连接用完之后要断开,正常断开需要四次挥手,而在这四次挥手的最后阶段,主动关闭连接的一方会进入一个叫TIME_WAIT的状态。

TIME_WAIT不是说马上消失,而是会等一段时间。这段等待时间在Windows上默认是240秒(4分钟),在Linux上通常由tcp_fin_timeout控制,默认60秒。为什么要等这么久?主要是怕最后一个ACK报文在网络里丢了,对方收不到就会重发FIN,这边如果直接关闭端口,重发的FIN就没人应答,会拖垮下一次连接。所以TCP协议设计了TIME_WAIT,让这个端口在等待期内一直占着,不允许立即复用。

问题就出在这个“占着”上。JMeter高并发压测时,如果请求是短连接(每次请求都新建TCP连接、用完就断开),那么每完成一笔事务,就会有一个端口进入TIME_WAIT状态,并且要在那边蹲满240秒才被释放。压测越猛,被占着的端口越多,直到动态端口池全部耗尽,新的连接没有端口可用,操作系统就会对发起方抛出一个BindException,也就是你看到的“Address already in use: connect”。

这里要特别提醒一句:这个报错的“Address already in use”指的是本地发起连接时找不到空闲端口,而不是被压测服务器上8080/80端口被占用。两者报错内容虽然都带“address already in use”,但一个是“connect”阶段的客户端端口耗尽,一个是“bind”阶段的服务端端口被占用,排查方向完全不同。

1.2 压测机端口池就这么大,算算就明白了

Windows上默认的动态端口范围,以常见的几代系统来说,一般只会开放一小段区间供应用自由使用,比如从49152到65535,满打满算也就一万六千多个端口。看起来很不少,但在压测场景下根本不够看。

假设你的压测目标是每秒完成1000个请求,每次请求都是一条新连接、请求完就断开。那么同时处于TIME_WAIT状态的端口数量,就等于“每秒新建连接数 × TIME_WAIT等待秒数”。按Windows默认的240秒来算,只要压测稳定跑上几十秒,TIME_WAIT状态的端口就会堆积到:1000 × 240 = 240000个。而你的端口池满打满算才一万六,早就被撑爆了,报错是必然的。

这个公式特别重要,我后来调优时一直拿它做估算。只要看清这几个数,基本就能判断问题严不严重:每秒新建连接数(可以理解为没有Keep-Alive时的TPS)、TIME_WAIT时间、端口池大小。这三者的乘积关系决定了你的压测机什么时候会开始报错。大多数人在压测刚开始的前一两分钟见不到这个错,就觉得没事,等跑到某个时间点突然大量抛异常,其实就是TIME_WAIT堆积到上限了。

1.3 先分清是压测机还是被测机的问题

我在企业里帮人排查过很多次,发现一个很常见的现象:大家一看到这个报错,第一反应是去调被测服务的连接数、线程池、端口监听配置,折腾半天完全没效果。这里有个简单的判断方法,报错日志里如果出现的是“Connection refused”,那通常是被测服务真的没起来或者监听端口不对;如果出现的是“Address already in use: connect”,那问题百分之九十出在压测发起方,也就是JMeter所在的那台机器。

还有一点容易被忽略,JMeter如果是用GUI模式跑的,界面本身的渲染、监听器大量写日志都会消耗资源,但更关键的是GUI模式会拖慢脚本执行节奏,导致连接建立和释放的规律和真实场景差异很大。我在压测时坚持用非GUI模式,也就是命令行模式,这样JMeter只会专心做施压,端口分配也更规矩,排查问题时变量也更少。

2. 压测机是Windows:注册表三板斧直接上

2.1 把动态端口范围拉高

Windows上端口池的限制可以通过注册表调整,这也是网上被提到最多的解决方案。打开注册表编辑器,定位到:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

找一下有没有一个叫MaxUserPort的DWORD值,没有的话就新建一个,类型选DWORD(32位),把值改成十进制的65534。这个参数决定了一个应用程序最多可以用到多大的动态端口号。

改完之后,还可以再用命令行确认一下动态端口池的真实区间。以管理员身份打开CMD,执行:

netsh int ipv4 show dynamicport tcp

如果显示出来的起始端口和数量比较小,可以用下面这条命令把它直接拉大:

netsh int ipv4 set dynamicport tcp start=1025 num=64510

这里的start是起始端口,num是端口总数,加起来是65535。注意这条命令设置的范围越大,效果越直接,但也意味着系统其他软件可用的高端口会变少,不过在实际压测场景里,压测机就是专门干这个活的,影响可以忽略。

2.2 把TIME_WAIT的等待期压短

光把端口池扩大,只是让报错来得晚一些,真正要解决的是缩短TIME_WAIT的占用时间。还是在刚才的注册表路径下,新建或修改TcpTimedWaitDelay这个DWORD值,单位是秒,官方允许的范围是30到300之间,默认值是240。我们把它改成30,意思就是让端口在TIME_WAIT状态只停留30秒,释放速度快了8倍。

按前面那个公式再算一次:每秒新建连接数还是1000,TIME_WAIT从240秒变成30秒,占用的端口数就从240000降到30000。再配合端口池拉到六万五,基本可以支撑到2000多的每秒新建连接数而不报错。这个数字对大多数中小型项目压测来说已经够用了。

改完之后记得重启机器,或者至少重启相关服务,否则注册表参数不会生效。我见过有人改完不重启,然后跑来问为什么还是报错,十有八九是这个原因。另外,TcpTimedWaitDelay的单位是秒,注意填10进制而不是16进制,注册表编辑器默认显示的是16进制,直接填十进制数字更稳妥。

2.3 网上说的“端口复用偏方”为什么不靠谱

网上有不少帖子说,把TcpMaxDataRetransmissions改成2就能让Windows实现端口复用,这个说法流传很广,但实际上是错的。TcpMaxDataRetransmissions控制的是TCP数据报文最大重传次数,属于链路可靠性参数,跟TIME_WAIT端口回收没有直接关系,改了它不仅解决不了端口耗尽,还可能让弱网环境下的重传变少,影响传输稳定性,我在项目里曾经被这个偏方带偏过,折腾了半天不仅没见效,反而多出了超时问题。

Windows要比Linux简单粗暴,它没有像Linux那样的tcp_tw_reuse开关可以主动回收TIME_WAIT端口,本质上的优化手段就是两条:扩大端口池、缩短等待时间。与其去研究那些不靠谱的偏方,不如让脚本侧尽量少建连接,再配合合适的压测架构,这才是正路。

3. 脚本侧调整:让JMeter少建连接

3.1 JMeter的连接模型长什么样

很多JMeter使用者对“线程数”和“TCP连接数”的关系是模糊的,以为线程多就是连接多,其实不一定。JMeter里,每个线程模拟一个虚拟用户,这个虚拟用户在执行HTTP请求时,如果开启了Keep-Alive,那么在同一个线程的多次迭代中,是可以复用同一条TCP连接的。也就是说,1000个线程压测,并不一定会有1000条连接同时存在,连接是否新建,取决于这个线程当前的请求是否已经和服务器建立了连接。

理解了这个模型,就能明白一个关键结论:压测机的端口耗尽,和“线程数”没有直接关系,和“每秒新建连接数”才有直接关系。如果一个线程的每个迭代都新建连接,那一秒内所有线程发起的请求次数,就是每秒新建连接数;如果一个线程只建立一条连接然后复用,那一秒内新建的连接数最多也就是线程数,不会因为请求量变大而暴涨。

所以调整脚本的第一原则就是:尽量让JMeter复用连接,而不是频繁创建新连接。

3.2 Keep-Alive和Connection: close的坑

HTTP Request取样器里有一个“Use KeepAlive”选项,默认是勾选的,正常情况下JMeter会尽量复用连接。但这里有个坑:就算你在JMeter这边勾选了Keep-Alive,如果被测服务返回的响应头里带了Connection: close,那这条连接用完之后照样会被关闭,JMeter也没办法硬复用。这种情况下你去改脚本是没用的,必须让服务端把响应头改成Connection: keep-alive,或者确认服务端的连接策略确实支持长连接。

还有一种情况是服务端配置了空闲超时,比如Tomcat的keepAliveTimeout设置比较短,连接空闲一会儿就被服务端主动关闭了,客户端感知后会在下一次请求时重新建连。这样即使整体看Keep-Alive是开着的,实际每秒新建连接数依然很高。我排查时习惯在压测过程中抓包,或者直接看服务端连接数曲线,确认TCP连接是不是在频繁建立和销毁,这一步比猜配置要靠谱得多。

3.3 线程数、Ramp-Up与新建连接速率

另一个容易踩的坑是Ramp-Up时间设置得过短。很多新手习惯把Ramp-Up设成0,意思是一秒内所有线程全部启动。线程一启动就会立刻抢占系统资源、抢建连接,一瞬间的把所有线程所需的连接全都塞到TCP层去,端口池一下子就满了。

我一般建议把Ramp-Up时间设置成一个合理的值,让线程平缓建立。比如500个线程,Ramp-Up设为50到100秒,每秒新增5到10个线程,这样端口分配是平缓的,压测曲线也不会出现开头一个大尖峰。合理控制线程启动节奏之后,我们看到TIME_WAIT的堆积速度明显下降,大妈大妈式的烫手山芋现象很少再现。

但也要提醒:Ramp-Up只是缓兵之计,并不能根治端口耗尽。它的核心价值是让压测曲线更接近真实用户进入系统的节奏,同时避开瞬时端口高峰,真正决定上限的还是每秒新建连接数和端口池的大小关系。

4. 一台压测机不够,就上分布式压测

4.1 为什么分布式能缓解端口耗尽

单台压测机的端口池再大,也有上限。Windows上即使把动态端口拉到六万五,TIME_WAIT压到30秒,理论上限也就每秒两千多新连接,这对于一些高并发、短连接的服务来说还是远远不够。这时候就需要换一个思路:不在一棵树上吊死,把压力分散到多台压测机上去。

JMeter的分布式压测模型是典型的master-slave结构。一台JMeter作为调度端,不下发请求流量;另几台机器运行jmeter-server,作为实际施压端。每一台slave都有自己独立的动态端口池,端口资源等于翻了几倍。比如你有4台压测机,相当于就有4个端口池,理论支撑的每秒新建连接数可以到八千甚至更高,这在日常项目里已经非常够用。

4.2 一套可以直接套用的分布式压测方案

搭建分布式没有网上说的那么玄乎,基本都是这几步。先准备一台调度机和几台压力机,压力机上装好Java和JMeter,保证版本一致,特别是JMeter的大版本最好统一,否则脚本运行经常出怪问题。

压力机上启动jmeter-server,默认监听的端口是1099,启动命令:

jmeter-server -Djava.rmi.server.hostname=压力机IP

然后回到调度机的JMeter配置里,找到bin目录下的jmeter.properties,找到remote_hosts这个配置项,把压力机的IP和端口填进去,多个压力机用逗号分隔:

remote_hosts=192.168.1.10:1099,192.168.1.11:1099

保存后重启JMeter,在GUI模式下点“远程启动”就能看到多台压力机开始配合干活了。实际压测时我不用GUI,直接命令行:

jmeter -n -t script.jmx -r -l result.jtl

这里的-r就是启动所有配置在remote_hosts里的远程压力机。每次跑完记得看聚合报告里有没有连接到哪一台压力机的异常,如果某台机器总在报错,单独去掉那台重跑,就能验证是不是那台压测机的系统参数没调好。

4.3 更彻底的做法:把压测机放到Linux上

如果条件允许,最省心的方案是把压测机的操作系统换成Linux。Linux的TCP协议栈比Windows更开放,端口池默认也更大,而且支持真正意义上的TIME_WAIT复用。用sysctl命令可以把系统参数调整成非常适合压测的状态:

sysctl -w net.ipv4.ip_local_port_range="1024 65535" sysctl -w net.ipv4.tcp_fin_timeout=30 sysctl -w net.ipv4.tcp_tw_reuse=1

这个tcp_tw_reuse是真正的端口复用,允许新连接安全地使用TIME_WAIT状态的端口,这是Windows没有的能力。不过要注意,tcp_tw_reuse依赖TCP时间戳功能,如果内核里net.ipv4.tcp_timestamps被关掉了,复用是起不来的,正常云主机默认都是开的。参数改完记得sysctl -p让它生效。

我在实际项目里给一个模拟的网关接口做过压测,单台Windows上短连接跑到每秒3000左右就开始零星报这个错,换了Linux压测机之后,同样的脚本直接拉到每秒5000还很稳,连操作系统都不用重启。所以如果你的压测规模经常超过每秒两三千新连接,别犹豫,直接上Linux,省掉后面所有折腾。

5. 排查思路与高频问题速查

5.1 从报错日志到根因定位的完整流程

遇到“address already in use”,我建议按这个顺序排查。先看报错到底出现在哪个环节:打开JMeter的查看结果树,过滤出报错的样本,看异常类型是java.net.BindException: Address already in use: connect还是Connection refused,这个动作一分钟就能做,不要跳过去直接改配置。

确认是客户端端口问题之后,登录压测机敲一条命令,统计当前TIME_WAIT状态的连接数:

netstat -an | findstr TIME_WAIT | find /c "TIME_WAIT"

Windows的find /c是计数的意思,统计出来的数字如果已经接近或超过一万,基本可以断定是端口池被TIME_WAIT塞满了。用netstat -ano还能看到这些TIME_WAIT连接是被哪个PID占用的,配合任务管理器确认是不是JMeter的Java进程。

接下来回到脚本,统计一下当前压测场景的TPS,再结合压测机上动态端口池大小和TIME_WAIT秒数,用前面那个公式算一遍,确认是不是入口容量不够。如果算出来理论上够,但还是报错,那就检查是不是被测服务主动关闭了连接,导致实际新建连接数远超预期。这一步我通常是直接抓包或者在被测服务端看连接曲线,非常直观。

5.2 高频问题速查表

症状可能原因解决思路
压测跑了几分钟后开始报address already in useTIME_WAIT堆积,端口池耗尽拉高动态端口范围,缩短TcpTimedWaitDelay
一开始压测就报address already in useRamp-Up太短,线程瞬间抢连接增大Ramp-Up,平缓启动线程
脚本勾了Keep-Alive但仍然大量新连接服务端返回Connection: close调整服务端连接策略,确认响应头
单台压测机每秒新建连接数超过上限端口池物理容量不足上分布式压测,或者换Linux压测机
修改注册表后还是报错没重启系统,或者改的不是Tcpip参数路径确认路径正确,重启后再验证
JMeter报错但服务端看很空闲压测机自己端口瓶颈,不是服务端问题把排查重点从服务端移到压测机

这张表我贴了不少次,基本覆盖了大家遇到的高频情况。如果你不在表里,大概率是环境特殊,比如压测机和被测服务之间还有一层负载均衡,连接被负载均衡主动断开,这种就需要去调中间链路层的参数,而不是纠结JMeter。

5.3 压测前的五分钟检查清单

最后分享一个习惯,我每次压测前都会花五分钟过一遍这个清单,基本能提前挡掉八成以上的端口类问题。第一,确认压测机是不是专用的,不要在你自己办公用的电脑上压测,随便装个软件、跑个浏览器都在抢端口。第二,确认动态端口范围,Windows上跑一条netsh int ipv4 show dynamicport tcp,Linux上跑sysctl net.ipv4.ip_local_port_range,看一眼大小。第三,确认脚本里HTTP请求的连接策略,是打算走Keep-Alive还是短连接,短连接场景要提前估算每秒新建连接数。第四,确认压测机的TIME_WAIT秒数,Windows看注册表,Linux看net.ipv4.tcp_fin_timeout。第五,想清楚单台机器够不够,不够就直接规划分布式压测,别等跑挂了再拆。

这套检查看起来琐碎,但养成习惯之后,你会发现自己排查“address already in use”的速度快很多,不会再被一个报错卡住半天。我记得自己在某个模拟项目上第一次完整按这个流程走了一遍,从看结果树、数TIME_WAIT、改注册表、重启、重跑,到最终压测顺利完成,前后不到半小时,而之前靠瞎试配置浪费了整整一个下午。希望这篇能帮你把之前浪费掉的下午省回来。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 7:48:50

车载以太网分层解析:从物理层到应用层的配置与排障指南

简介:围绕车载以太网技术体系展开的系统性概述资料,面向汽车电子工程师、嵌入式网络开发人员及智能驾驶相关从业者,帮助读者快速建立从物理层到应用层的完整认知框架。资料共1个PDF文件,压缩包大小约3.85MB,为高清图文…

作者头像 李华
网站建设 2026/10/22 7:48:47

无线网络实验报告全攻略:参数、抓包与避坑指南

简介:无线网络技术全部实验报告要点合集,聚焦无线网络应用课程中的典型实验任务,内容涉及虚拟服务器与防火墙安全配置、WEP/WPA-PSK加密模式、DMZ主机与IP过滤、DHCP服务器配置以及无线AP的Bridge/Client组网模式等,适合高校网络工…

作者头像 李华
网站建设 2026/10/22 7:45:43

SpringBoot+Vue电影评论网站毕设全攻略:前后端分离实战

毕业设计选电影评论网站,听起来很大路货,但真正动手做过的人都知道,这个题目远没有表面那么“简单”——恰恰因为大家都做,答辩老师一眼就能看出你是真会还是假会。我前前后后帮朋友和学生改过好几套类似的项目,自己也…

作者头像 李华
网站建设 2026/10/22 7:45:30

ANSYS后处理基础:从云图到工程判断的避坑指南

简介:这份《ansys后处理基础.pdf》面向刚完成ANSYS求解、需要读懂并解释计算结果的初学者与工程技术人员,聚焦后处理这一分析流程中最关键的收尾环节。内容围绕POST1通用后处理器与POST26时间历程后处理器展开,讲解如何将结果文件读入数据库、…

作者头像 李华
网站建设 2026/10/22 7:45:12

MySQL被几千台设备拖垮?时序数据库选型与落地指南

先说一个判断:几千台设备把 MySQL 拖垮,大多数时候不是 MySQL 配置不够、SQL 写得太差,而是存储模型和数据访问模式不匹配。时序数据是“写多读少、追加为主、按时间扫描、需要聚合”的数据,天生适合列式存储、时间分区和专用压缩…

作者头像 李华
网站建设 2026/10/22 7:44:31

用Claude Code和免费托管,零代码也能上线个人网站

一直以来,做网站这件事,在大多数人印象里属于程序员的专属领域:要会 HTML、CSS、JavaScript,要懂服务器,还要花钱买域名、买空间。但这两年 AI 编程工具快速成熟,这个门槛正在被大幅拉低。哪怕一行代码都没…

作者头像 李华