3. iperf3 进阶:多线程测试、反向模式、带宽报告解读、JSON 输出解析、自动化脚本编写
好,咱们继续深入。上一章我们把 iperf3 的基础用法捋了一遍,测个简单带宽没问题了。但说实话,真实的生产环境远比那复杂。你想想看,现在的服务器哪个不是多核的?网络链路哪个不是双向的?
这一章,我们就来啃硬骨头。我会把多线程、反向模式、报告解读、JSON 解析,还有我最拿手的自动化脚本,一次性给你讲透。
3.1 多线程测试:模拟真实并发
为什么需要多线程?
我刚开始做性能测试那会儿,就犯过一个低级错误。用单线程去压一个 40 核的服务器,结果带宽死活上不去。我还以为是网卡坏了,折腾了半天。后来老工程师一句话点醒我:「你一个线程,能占满所有 CPU 吗?」
iperf3 默认是单线程的。单线程只能跑在一个 CPU 核心上。对于多核系统,这根本发挥不出全部性能。
核心参数:-P(大写 P)
这个参数指定并发线程数。我个人习惯,一般先设成和目标服务器的 CPU 核心数一样。
# 服务端(和之前一样)
iperf3 -s
# 客户端,启动 4 个线程并发测试
iperf3 -c 192.168.1.100 -P 4 -t 30
看到输出结果了吗?它会分别显示每个线程的带宽,最后汇总一个总和。
重要经验:线程数不是越多越好。我曾经在一个 64 核的机器上测试,把 -P 设成 128,结果带宽反而下降了。为什么?因为线程切换开销太大了。一般来说,-P 值设为 CPU 核心数的 1 到 2 倍比较合理。
3.2 反向模式:测双向才真实
默认情况下,iperf3 是客户端向服务端发送数据,测的是下行(从客户端角度看)。但网络是双向的,对吧?
你想想看,一个 Web 服务器,用户请求是上行,服务器响应是下行。如果只测一个方向,你根本不知道另一个方向是不是瓶颈。
核心参数:-R
加上 -R,数据流就反过来了——服务端向客户端发数据。
# 测试反向带宽(服务端 -> 客户端)
iperf3 -c 192.168.1.100 -R -t 30
我建议的做法是:先测正向,再测反向,对比着看。如果两个方向差距很大,那就要怀疑是不是网卡配置、驱动或者交换机端口有问题了。
小技巧:可以用 -d 参数同时进行双向测试。但要注意,这会让结果互相干扰,适合做压力测试,不适合做精确测量。
3.3 带宽报告解读:别只看最后一行
很多人跑完 iperf3,只看最后那个 SUM 行的平均值。嗯,这其实不够。
我们来拆解一份典型的报告:
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-1.00 sec 112 MBytes 940 Mbits/sec 0
[ 5] 1.00-2.00 sec 110 MBytes 923 Mbits/sec 1
[ 5] 2.00-3.00 sec 113 MBytes 948 Mbits/sec 0
[ 5] 3.00-4.00 sec 108 MBytes 906 Mbits/sec 2
[ 5] 4.00-5.00 sec 111 MBytes 931 Mbits/sec 0
[ 5] 5.00-6.00 sec 109 MBytes 914 Mbits/sec 1
[ 5] 6.00-7.00 sec 112 MBytes 940 Mbits/sec 0
[ 5] 7.00-8.00 sec 110 MBytes 923 Mbits/sec 0
[ 5] 8.00-9.00 sec 113 MBytes 948 Mbits/sec 0
[ 5] 9.00-10.00 sec 111 MBytes 931 Mbits/sec 1
[ 5] 10.00-10.04 sec 4.50 MBytes 941 Mbits/sec 0
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.04 sec 1.09 GBytes 931 Mbits/sec 5 sender
[ 5] 0.00-10.04 sec 1.09 GBytes 931 Mbits/sec receiver
关键看三点:
- Interval 列:默认每 1 秒一个采样点。看这些值是否稳定。如果忽高忽低,说明网络有抖动。
- Retr 列:重传次数。这是我最关注的指标。重传多,说明网络有丢包或者拥塞。我曾经遇到过一个案例,带宽看起来有 900M,但 Retr 高达几百,用户体验极差。
- 最后一行的 sender 和 receiver:sender 是发送端统计的,receiver 是接收端统计的。正常情况下两者应该一致。如果不一致,说明有丢包。
注意:如果 Retr 列一直为 0,不一定代表网络完美。可能是因为 iperf3 的 TCP 窗口设置得太小,根本没把网络压满。这时候可以试试增大窗口:-w 1M。
3.4 JSON 输出解析:让数据说话
人类读文本报告还行,但机器不行。我们要做自动化,就得用 JSON 格式。
核心参数:-J
iperf3 -c 192.168.1.100 -J -t 10
输出会变成这样(简化版):
{
"start": {
"connected": [{"local_host": "192.168.1.2", "remote_host": "192.168.1.100"}]
},
"intervals": [
{
"sum": {
"start": 0,
"end": 1,
"bits_per_second": 940000000,
"retransmits": 0
}
},
...
],
"end": {
"sum_received": {
"bits_per_second": 931000000,
"retransmits": 5
}
}
}
JSON 结构很清晰:
start:连接信息intervals:每个时间段的详细数据end:汇总数据,包括sum_sent和sum_received
我最常用的是 end.sum_received.bits_per_second,这就是最终的接收带宽。
3.5 自动化脚本编写:解放双手
好了,理论讲完了。现在来点实战的。我写了一个 Python 脚本,可以自动跑多轮测试,解析 JSON,生成报告。
为什么要自动化?
我记得有一次,需要测试 10 台服务器之间的两两带宽。手动跑?那得跑 45 次,每次还要记录结果。我算了一下,大概要 3 个小时。用脚本,5 分钟搞定。
#!/usr/bin/env python3
"""
iperf3 自动化测试脚本
用法:python3 iperf_auto.py --server 192.168.1.100 --duration 30 --parallel 4
"""
import subprocess
import json
import argparse
import time
from datetime import datetime
def run_iperf_test(server, duration, parallel, reverse=False):
"""执行一次 iperf3 测试,返回解析后的结果"""
cmd = [
"iperf3",
"-c", server,
"-t", str(duration),
"-P", str(parallel),
"-J" # JSON 输出
]
if reverse:
cmd.append("-R")
print(f"[{datetime.now().strftime('%H:%M:%S')}] 开始测试: {'反向' if reverse else '正向'}")
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=duration + 10)
data = json.loads(result.stdout)
# 提取关键指标
end_data = data.get("end", {})
sum_received = end_data.get("sum_received", {})
return {
"timestamp": datetime.now().isoformat(),
"direction": "reverse" if reverse else "forward",
"bits_per_second": sum_received.get("bits_per_second", 0),
"bytes": sum_received.get("bytes", 0),
"retransmits": sum_received.get("retransmits", 0),
"raw_json": data
}
except Exception as e:
print(f"测试失败: {e}")
return None
def main():
parser = argparse.ArgumentParser(description="iperf3 自动化测试")
parser.add_argument("--server", required=True, help="iperf3 服务端地址")
parser.add_argument("--duration", type=int, default=30, help="测试时长(秒)")
parser.add_argument("--parallel", type=int, default=1, help="并发线程数")
parser.add_argument("--rounds", type=int, default=3, help="测试轮数")
parser.add_argument("--interval", type=int, default=10, help="轮次间隔(秒)")
args = parser.parse_args()
print("=" * 60)
print(f"iperf3 自动化测试开始")
print(f"目标服务器: {args.server}")
print(f"测试时长: {args.duration}s")
print(f"并发线程: {args.parallel}")
print(f"测试轮数: {args.rounds}")
print("=" * 60)
all_results = []
for round_num in range(1, args.rounds + 1):
print(f"\n--- 第 {round_num} 轮测试 ---")
# 正向测试
forward_result = run_iperf_test(
args.server, args.duration, args.parallel, reverse=False
)
if forward_result:
all_results.append(forward_result)
# 休息一下,避免影响下一轮
time.sleep(2)
# 反向测试
reverse_result = run_iperf_test(
args.server, args.duration, args.parallel, reverse=True
)
if reverse_result:
all_results.append(reverse_result)
# 轮次间隔
if round_num < args.rounds:
print(f"等待 {args.interval} 秒后进行下一轮...")
time.sleep(args.interval)
# 生成汇总报告
print("\n" + "=" * 60)
print("测试结果汇总")
print("=" * 60)
forward_bw = [r["bits_per_second"] for r in all_results if r["direction"] == "forward"]
reverse_bw = [r["bits_per_second"] for r in all_results if r["direction"] == "reverse"]
if forward_bw:
avg_f = sum(forward_bw) / len(forward_bw) / 1e6
print(f"正向平均带宽: {avg_f:.2f} Mbps")
if reverse_bw:
avg_r = sum(reverse_bw) / len(reverse_bw) / 1e6
print(f"反向平均带宽: {avg_r:.2f} Mbps")
print("\n测试完成!")
if __name__ == "__main__":
main()
使用建议:
- 先手动跑一次,确认服务端和客户端能正常通信
- 脚本中的
timeout参数要设得比测试时长稍长,防止卡死 - 如果测试大量服务器,建议把结果写入 CSV 文件,方便后续分析
3.6 本章知识体系
下面这张图,是我梳理的本章核心逻辑。你可以把它当成一个检查清单,看看自己掌握了哪些。
嗯,这一章的内容确实不少。多线程、反向模式、报告解读、JSON 解析,再到最后的自动化脚本,每一步都是实战中必不可少的技能。
我个人建议,你先把脚本跑起来,看看输出结果。然后试着改一改,比如加个 CSV 导出功能,或者做个简单的 Web 展示页面。只有动手做了,才能真正掌握。
想要更多资料,联系可可