tcp_autocork_test怎样测试

联启 网络工具 16

本文目录导读:

tcp_autocork_test怎样测试-第1张图片-电脑手机工具软件下载 - 免费实用工具合集 | 联启科技

  1. 核心测试思路
  2. 测试方法
  3. 注意事项和陷阱
  4. 一个完整的 Python 测试脚本示例
  5. 总结测试步骤

我们来详细探讨如何测试 tcp_autocorking(通常指 tcp_autocork 或相关的内核自动 corking 行为),这个测试的核心目标是验证 Linux 内核在处理小数据包写入时,是否会自动合并(cork)这些数据包,以减少网络传输中的小包数量,从而提高吞吐量并降低 CPU 开销。

tcp_autocorking 是一个相对新(约 2019 年加入,但在后续版本中持续优化)的内核特性,它允许内核在特定条件下自动执行 cork 操作,即使应用程序没有显式调用 TCP_CORK 或使用 sendfile() 等大块写入。

核心测试思路

测试 tcp_autocorking 的关键是比较开启关闭该特性时,网络传输的行为差异,主要关注点:

  1. 发送的数据包数量:开启后,小包应被合并,导致发送的 TCP 段(Segments)数量减少。
  2. 系统调用次数write/send 的调用次数不变,但实际发送的次数可能变化。
  3. 吞吐量:对于某些特定工作负载(如大量、小、高频率写入),开启后吞吐量应提升。
  4. 延迟:可能略有增加(因为要等待合并),但通常影响不大。

测试方法

你可以通过以下几种具体方法来测试。

使用 ssnetstat 观察统计信息

这是最直接的方法,在发送端和接收端运行。

步骤:

  1. 建立连接并模拟小包写入:

    • 编写一个简单的程序(如 Python/TCP 客户端)不断向服务器发送很小的数据包(1 字节)。
    • 确保服务器端接收。
  2. 观察发送端的 TCP 统计:

    • 使用 ss -tiepnetstat -st 查看 segments(段)数量。
    • 关键指标是 segments retransmittedsegments 总数量除以写入的数据量,如果数据包合并得当,发送的 TCP 段数量应远小于写入的数据块数。
    # 查看特定连接的统计
    watch -n 1 "ss -tiep | grep <your-connection>"
    # 或者查看全局 TCP 段统计
    netstat -s | grep -E "segments|packet"
    • 对比测试: 分别测试 tcp_autocorking = 1 (默认) 和 tcp_autocorking = 0 时的段数量。

tcpdump / tshark 抓包分析

这是最精确的方法,可以直接看到网络上的数据包。

步骤:

  1. 在发送端或接收端捕获流量:

    tcpdump -i any -w /tmp/test_autocork.pcap port 12345
  2. 运行测试程序(发送大量小数据包)。

  3. 分析 pcap 文件:

    • 使用 tshark 统计 data.len (TCP payload size) 的分布。
    • autocorking 生效,你应该会看到大部分数据包的有效载荷(payload)大于你发送的小块大小,你发送了 1000 次 1 字节的 send(),正常情况下你可能看到 1000 个 1 字节的数据包(如果没合并),或者看到几百个合并后的较大数据包(如几十到上百字节)。
    • 可以使用 tshark -r test.pcap -T fields -e tcp.payload 查看 payload 大小。
    • 关键统计: tshark -r test.pcap -T fields -e frame.len 可以快速知道包的大小分布,小包(如小于 100 字节)的比例下降,大包(如 MSS,即最大段大小)的比例显著上升。
  4. 对比测试:

    • 关闭 autocorking
      echo 0 > /proc/sys/net/ipv4/tcp_autocorking
    • 重复抓包,你会发现关闭后,data.len 极大概率等于你发送的单次写入大小(1 字节),导致大量极小的 ACK 和数据包。

使用系统性能工具(perf, ftrace, eBPF

可以追踪内核函数 tcp_push()__tcp_transmit_skb() 的调用情况,但这通常需要较深的内核知识。

eBPF 示例(简单思路):

你可以写一个简单的 eBPF 程序来统计 tcp_sendmsg 被调用的次数和实际发送的 SKB(socket buffer)数量,当 autocorking 工作时,tcp_push 会延迟发送,将多个用户态写入合并成一个 SKB。

编写一个简单的性能测试程序(推荐)

这是一个非常有效且可控的测试方案。

程序逻辑(C 或 Python):

  • Client (发送端):

    1. 创建 TCP 连接。
    2. 循环执行 10000 次:
      • 执行 write(sock, buffer, 1) (发送 1 字节)。
      • usleep(100) 微秒睡眠,模拟真实的高频小包场景。
    3. 记录总耗时和实际发送的数据量。
  • Server (接收端):

    1. 创建 TCP 监听套接字。
    2. 接收数据直到连接关闭。
    3. 记录接收到的总字节数和数据包数量(可以通过 recvfrom 得到每次 recv 的字节数,但这不是直接的网络包数量,更精确的是监听 tcpdump)。

测试对比:

  1. 开启 autocorking (默认):

    • 启动服务器,运行客户端。
    • 记录客户端耗时、服务器端收到的数据包数量(通过 tcpdump)。
  2. 关闭 autocorking:

    • echo 0 > /proc/sys/net/ipv4/tcp_autocorking
    • 重复测试。

预期结果:

特性 耗时 (秒) 发送的 TCP 段数量 服务器端收到的包数量
tcp_autocork=1 较短 较少 (如 500) 较少 (如 500)
tcp_autocork=0 较长 较多 (如 9500) 较多 (如 9500)

为什么耗时变短? 因为合并后的数据包可以一次(或几次)进行 Nagle 算法合并、TSO(TCP分段卸载)等,减少了中断处理和内核协议栈的开销。

注意事项和陷阱

  1. Nagle 算法的干扰: tcp_autocorking 是独立于 Nagle 算法 (TCP_NODELAY) 的。默认 Nagle 是开启的,Nagle 算法会等待接收 ACK 后再发送后续数据,为了隔离测试 autocorking,最好将两者结合或分别测试。

    • 如果测试发送端开启 TCP_NODELAY,则 Nagle 被禁止,autocorking 成为主要的合并机制。
    • 如果测试发送端不开 TCP_NODELAY,Nagle 也会合并小包,效果类似,但逻辑不同,建议测试时明确控制 TCP_NODELAY
  2. 发送速率和睡眠时间: autocorking 的生效依赖于时机,如果写入频率太快(没有睡眠),数据会立即被发送出去(称为 push 标志自动设置),如果写入之间睡眠足够长(如 10ms),则可能触发 corking 合并,你的测试程序中的 usleep 长度会影响合并效果,建议尝试 100us ~ 10ms 的范围。

  3. 内核版本: 确保你的 Linux 内核版本支持 tcp_autocorking (4.19+),较新版本 (5.x, 6.x) 行为可能有些微调。

  4. 对端接收能力: 接收窗口的大小会影响发送行为,如果接收窗口足够大,合并效果更好。

一个完整的 Python 测试脚本示例

import socket
import time
import sys
def test_autocork(host='127.0.0.1', port=12345, nagle_on=True, payload_size=1, iterations=10000, sleep_us=100):
    # 1. 创建套接字
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1 if not nagle_on else 0)
    sock.connect((host, port))
    buf = b'x' * payload_size
    # 2. 计时并发送
    start = time.time()
    for i in range(iterations):
        sock.send(buf)
        if sleep_us > 0:
            time.sleep(sleep_us / 1_000_000.0)  # 微秒睡眠
    end = time.time()
    # 3. 关闭连接
    sock.close()
    elapsed = end - start
    print(f"Nagle: {nagle_on}, 总花费: {elapsed:.3f}秒, 吞吐量: { (iterations * payload_size) / elapsed / 1024 / 1024:.2f} MB/s")
    print(f"参考: 理论上如果未合并, 应发送 {iterations} 个包; 合并后包数 = 总数据量 / MSS")
if __name__ == '__main__':
    host = sys.argv[1] if len(sys.argv) > 1 else '127.0.0.1'
    port = int(sys.argv[2]) if len(sys.argv) > 2 else 12345
    # 测试关闭 Nagle (只测 autocorking)
    print("--- 测试 tcp_autocorking (关闭 Nagle) ---")
    test_autocork(host, port, nagle_on=False)   # 只依赖 autocorking
    # 测试开启 Nagle
    print("--- 测试 Nagle + autocorking ---")
    test_autocork(host, port, nagle_on=True)   # 两者都有

同时运行一个简单的接收服务器:

import socket
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('0.0.0.0', 12345))
s.listen(1)
conn, addr = s.accept()
data = conn.recv(4096)
while data:
    data = conn.recv(4096)
conn.close()
s.close()

总结测试步骤

  1. 抓包对比: 使用 tcpdump 抓取关闭 Nagle 后的流量,对比 autocorking=1autocorking=0 时数据包的大小分布。
  2. 性能对比: 使用上面的 Python 程序,对比相同的小负载,每次写入 1 字节,比较总耗时和吞吐量。
  3. 内核参数确认: 确保你测试时切换了 /proc/sys/net/ipv4/tcp_autocorking 并观察效果。
  4. 注意网络环境: 最好在回环接口 (lo) 或同一台机器的虚拟机上进行测试,以排除网络拥塞的干扰。

通过以上方法,你可以清晰地量化 tcp_autocorking 是否工作以及效果如何,关键在于观察小包被合并为大包这一核心现象。

标签: TCP自 动corking

抱歉,评论功能暂时关闭!