4. netperf 实战:TCP_STREAM、TCP_RR、UDP_STREAM 与自定义参数

好,咱们进入实操环节。netperf 这工具,我用了快十年了。说实话,它比 iperf 更对我的胃口——不是因为功能多,而是因为它把「连接管理」和「数据传输」拆得清清楚楚。你想想看,做协议栈调优,最怕的就是工具把底层细节藏起来。netperf 不藏,它把每个阶段的耗时都摆在你面前。

这一章,我会带你跑四个最核心的测试场景:TCP_STREAM、TCP_RR、UDP_STREAM,以及怎么用自定义参数把 netperf 玩出花来。每个场景我都会给命令、给解读、给避坑。

核心认知:netperf 的测试模式分为两类——批量传输(STREAM)和 请求-响应(RR)。前者看吞吐上限,后者看事务处理能力。调优时,这两类数据缺一不可。

netperf 测试模式全景图 netperf 测试模式 批量传输 (STREAM) 请求-响应 (RR) TCP_STREAM UDP_STREAM SCTP_STREAM TCP_RR UDP_RR 说明: STREAM 模式关注「能跑多快」——吞吐量(Mbps);RR 模式关注「能处理多少笔」——事务率(TPS)。 调优时,两个维度都要测,缺一不可。

4.1 TCP_STREAM:测透 TCP 的极限吞吐

TCP_STREAM 是 netperf 最基础的测试。它模拟的是「一条 TCP 连接,发送端拼命发,接收端拼命收」的场景。说白了,就是看你的网络栈在理想条件下能跑多快。

先看命令。我习惯把服务端挂在后台,用 -D 参数让它不 fork 子进程,减少上下文切换的干扰:

# 服务端(被测试机)
netserver -D

# 客户端(测试发起机)
netperf -H 192.168.1.100 -l 60 -t TCP_STREAM

参数解释:

  • -H:指定服务端 IP
  • -l 60:测试持续 60 秒
  • -t TCP_STREAM:指定测试类型

输出长这样:

TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.1.100 (192.168.1.100) port 0 AF_INET
Recv   Send    Send                          
Socket Socket  Message  Elapsed              
Size   Size    Size     Time     Throughput  
bytes  bytes   bytes    secs.    10^6bits/sec  

 87380  16384  16384    60.00    941.23

关键看最后一列:Throughput,单位是 Mbps。941.23 Mbps,接近千兆线速。如果这个值远低于链路带宽,那你的协议栈肯定有瓶颈。

我的习惯:TCP_STREAM 测试至少跑 3 次,取中位数。单次结果受 CPU 调度、中断亲和性影响很大。我曾经在同一个机器上连续跑 5 次,结果从 920 跳到 980 又掉回 910——后来发现是 irqbalance 在捣乱。

4.2 TCP_RR:事务处理能力的照妖镜

TCP_RR 测试的是「请求-响应」模式。客户端发一个请求,服务端回一个响应,算一次事务(Round Trip)。这个测试对延迟极其敏感——你想想看,如果一次往返要 1 毫秒,那理论最大事务率就是 1000 TPS。实际值低于这个数,说明协议栈在处理小包时有问题。

命令:

netperf -H 192.168.1.100 -l 60 -t TCP_RR

输出示例:

TCP REQUEST/RESPONSE TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.1.100 (192.168.1.100) port 0 AF_INET
Local /Remote
Socket Size   Request  Resp.   Elapsed  Trans.
Send   Recv   Size     Size    Time     Rate  
bytes  Bytes  bytes    bytes   secs.    per sec   

16384  87380  1        1       60.00    4521.34

关键列:Trans. Rate,单位是 trans/s(事务每秒)。4521 TPS,意味着每次往返约 221 微秒。如果这个值低于预期,我通常会先查两个东西:

  • NAPI 的 gro_flush_timeout:默认值可能把小包攒太久了
  • 中断合并(coalescing):ethtool -C 里的 rx-usecs 设太大,延迟会飙升

我曾经踩过的坑:有一次 TCP_RR 只有 800 TPS,链路延迟明明只有 0.3ms。查了两天,最后发现是服务端开了 tcp_nagle,请求被延迟发送了。关掉之后直接飙到 4200 TPS。所以测 RR 之前,记得检查 TCP_NODELAY 是否生效。

4.3 UDP_STREAM:无连接,但有坑

UDP_STREAM 测试的是 UDP 的发送吞吐。注意,netperf 的 UDP_STREAM 只统计发送端的数据——接收端丢了多少包,它不管。你需要配合 -k 参数看丢包统计。

命令:

netperf -H 192.168.1.100 -l 60 -t UDP_STREAM -- -m 1472

-m 1472 指定 UDP 载荷大小。1472 是标准 MTU 1500 减去 IP 头 20 和 UDP 头 8 后的最大值。用这个值可以避免 IP 分片。

输出:

UDP UNIDIRECTIONAL SEND TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.1.100 (192.168.1.100) port 0 AF_INET
Socket  Message  Elapsed      Messages                
Size    Size     Time         Okay Errors   Throughput
bytes   bytes    secs            #      #   10^6bits/sec

 65536   1472   60.00       812345   0      159.42

看 Throughput 和 Errors。Errors 为 0 说明发送端没报错,但不代表接收端都收到了。要确认接收情况,得在服务端用 netstat -s 看 UDP 丢包计数。

关键认知:UDP_STREAM 测的是「发送能力」,不是「传输质量」。如果接收端丢包严重,你需要关注的是接收缓冲区大小(rmem_max)和 GRO 的收包效率。

4.4 自定义参数:把 netperf 变成你的瑞士军刀

默认参数只能测个大概。真正做调优时,你得能控制每一个变量。netperf 的自定义参数通过 -- 后面的选项传入,我列几个最常用的:

参数 作用 典型值 我的用法
-m 设置发送消息大小(字节) 1, 64, 1024, 65536 测小包性能时用 1 或 64
-M 设置接收消息大小(字节) 同 -m TCP_RR 中控制请求/响应大小
-s 设置本地 Socket 缓冲区大小 87380, 262144 验证缓冲区对吞吐的影响
-S 设置远端 Socket 缓冲区大小 同 -s 配合 -s 一起调
-D 启用 TCP_NODELAY 无参数 测 RR 时必加
-k 指定输出哪些统计字段 THROUGHPUT, P50_LATENCY 获取延迟分布数据

举个例子,我想测「64 字节小包、启用 TCP_NODELAY、持续 120 秒」的 TCP_RR:

netperf -H 192.168.1.100 -l 120 -t TCP_RR -D -- -m 64 -M 64 -k THROUGHPUT,MIN_LATENCY,MAX_LATENCY,P50_LATENCY,P99_LATENCY

输出会多出延迟分布信息:

THROUGHPUT=4521.34
MIN_LATENCY=187
MAX_LATENCY=2341
P50_LATENCY=221
P99_LATENCY=389

看到 P99 比 P50 高了近一倍?这说明有尾部延迟问题。我一般会接着查中断亲和性、CPU 隔离、或者网卡的 RSS 哈希是否均匀。

我的经验:自定义参数测试一定要做「变量控制」。一次只改一个参数,记录结果。我习惯用脚本批量跑,输出 CSV 格式,然后用 Python 画趋势图。比如「消息大小 vs 吞吐量」这条曲线,能直接告诉你协议栈在小包场景下的瓶颈在哪。

4.5 实战组合:一次完整的调优测试流程

最后,我分享一个我常用的测试流程。每次调优前后,我都会跑这组测试,确保改动没有引入副作用:

  1. 基线 TCP_STREAM:-m 65536,测大包吞吐
  2. 小包 TCP_STREAM:-m 64,测小包吞吐
  3. TCP_RR 默认:1 字节请求/响应,测事务率
  4. TCP_RR 大载荷:-m 4096 -M 4096,测大载荷下的响应能力
  5. UDP_STREAM:-m 1472,测 UDP 发送能力
  6. UDP_RR:-m 64 -M 64,测 UDP 事务率

这六组数据跑完,你的网络栈是什么水平,瓶颈在哪,基本就清楚了。剩下的就是针对性地调参数、测回归、再调参数——循环直到达标。

注意:测试过程中,一定要用 perf top 或 mpstat -P ALL 1 监控 CPU 使用情况。如果某个 CPU 核心跑到 100%,而其他核心空闲,说明中断亲和性或 RFS/RPS 配置有问题。我曾经遇到过 TCP_STREAM 吞吐上不去,结果发现所有中断都打在一个核心上——调整 smp_affinity 后直接提升 30%。