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

关键看三点:

  1. Interval 列:默认每 1 秒一个采样点。看这些值是否稳定。如果忽高忽低,说明网络有抖动。
  2. Retr 列:重传次数。这是我最关注的指标。重传多,说明网络有丢包或者拥塞。我曾经遇到过一个案例,带宽看起来有 900M,但 Retr 高达几百,用户体验极差。
  3. 最后一行的 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 本章知识体系

下面这张图,是我梳理的本章核心逻辑。你可以把它当成一个检查清单,看看自己掌握了哪些。

iperf3 进阶测试知识体系 iperf3 进阶 多线程测试 (-P) 反向模式 (-R) 带宽报告解读 JSON 输出 (-J) 模拟多核并发 线程数 = CPU核心数 × 1~2 服务端 → 客户端 正向+反向对比分析 Interval 稳定性 Retr 重传次数 sender vs receiver 结构化数据解析 自动化脚本基础 最终目标:自动化、可重复、可对比的性能测试 从手动测试到脚本化,从单点到全链路

嗯,这一章的内容确实不少。多线程、反向模式、报告解读、JSON 解析,再到最后的自动化脚本,每一步都是实战中必不可少的技能。

我个人建议,你先把脚本跑起来,看看输出结果。然后试着改一改,比如加个 CSV 导出功能,或者做个简单的 Web 展示页面。只有动手做了,才能真正掌握。

想要更多资料,联系可可