我的应用程序所做的是从 kafka 读取数据并通过 HTTP 访问另一个服务。我发现一个盒子中的传出流量比其他盒子慢。我分析了 tcpdump 到该传出 IP,来自此框的日志:
09:24:20.625288 IP (tos 0x0, ttl 64, id 16107, offset 0, flags [DF], proto TCP (6), length 7292)
localIP.57854 > externalIp.http: Flags [.], cksum 0x03fb (incorrect -> 0x614e), seq 52963:60203, ack 464, win 2518, options [nop,nop,TS val 205440553 ecr 262205407], length 7240: HTTP
09:24:20.640851 IP (tos 0x0, ttl 64, id 16112, offset 0, flags [DF], proto TCP (6), length 2948)
localIP.57854 > externalIp.http: Flags [.], cksum 0xf302 (incorrect -> 0xb2a7), seq 60203:63099, ack 464, win 2518, options [nop,nop,TS val 205440557 ecr 262205422], length 2896: HTTP
09:24:20.640897 IP (tos 0x0, ttl 64, id 16114, offset 0, flags [DF], proto TCP (6), length 2948)
localIP.57854 > externalIp.http: Flags [.], cksum 0xf302 (incorrect -> 0x46c8), seq 63099:65995, ack 464, win 2518, options [nop,nop,TS val 205440557 ecr 262205422], length 2896: HTTP
09:24:20.640930 IP (tos 0x0, ttl 64, id 16116, offset 0, flags [DF], proto TCP (6), length 2948)
localIP.57854 > externalIp.http: Flags [.], cksum 0xf302 (incorrect -> 0xedd7), seq 65995:68891, ack 464, win 2518, options [nop,nop,TS val 205440557 ecr 262205422], length 2896: HTTP
09:24:20.640940 IP (tos 0x0, ttl 64, id 16118, offset 0, flags [DF], proto TCP (6), length 2948)
localIP.57854 > externalIp.http: Flags [.], cksum 0xf302 (incorrect -> 0x22df), seq 68891:71787, ack 464, win 2518, options [nop,nop,TS val 205440557 ecr 262205422], length 2896: HTTP
09:24:20.640973 IP (tos 0x0, ttl 64, id 16120, offset 0, flags [DF], proto TCP (6), length 2948)
localIP.57854 > externalIp.http: Flags [.], cksum 0xf302 (incorrect -> 0x7fad), seq 71787:74683, ack 464, win 2518, options [nop,nop,TS val 205440557 ecr 262205422], length 2896: HTTP
09:24:20.641016 IP (tos 0x0, ttl 64, id 16122, offset 0, flags [DF], proto TCP (6), length 2948)
localIP.57854 > externalIp.http: Flags [.], cksum 0xf302 (incorrect -> 0x19e9), seq 74683:77579, ack 464, win 2518, options [nop,nop,TS val 205440557 ecr 262205422], length 2896: HTTP
09:24:20.641027 IP (tos 0x0, ttl 64, id 16124, offset 0, flags [DF], proto TCP (6), length 2948)
localIP.57854 > externalIp.http: Flags [.], cksum 0xf302 (incorrect -> 0xc26d), seq 77579:80475, ack 464, win 2518, options [nop,nop,TS val 205440557 ecr 262205422], length 2896: HTTP
09:24:20.644138 IP (tos 0x0, ttl 64, id 16132, offset 0, flags [DF], proto TCP (6), length 2223)
localIP.57854 > externalIp.http: Flags [P.], cksum 0xf02d (incorrect -> 0x6078), seq 89163:91334, ack 464, win 2518, options [nop,nop,TS val 205440557 ecr 262205425], length 2171: HTTP
09:24:20.660631 IP (tos 0x0, ttl 64, id 16134, offset 0, flags [DF], proto TCP (6), length 775)
localIP.57854 > externalIp.http: Flags [P.], cksum 0xea85 (incorrect -> 0x14c9), seq 90611:91334, ack 464, win 2518, options [nop,nop,TS val 205440562 ecr 262205426], length 723: HTTP
同时在其他框中我看到以下内容:
09:26:53.610483 IP (tos 0x0, ttl 64, id 27441, offset 0, flags [DF], proto TCP (6), length 14532)
localIP.50978 > externalIp.http: Flags [.], cksum 0xcb4f (incorrect -> 0x3b5c), seq 151537:166017, ack 1390, win 1444, options [nop,nop,TS val 1613152807 ecr 262243666], length 14480: HTTP
09:26:53.610609 IP (tos 0x0, ttl 64, id 27451, offset 0, flags [DF], proto TCP (6), length 16713)
localIP.50978 > externalIp.http: Flags [P.], cksum 0xd3d4 (incorrect -> 0xed92), seq 166017:182678, ack 1390, win 1444, options [nop,nop,TS val 1613152807 ecr 262243668], length 16661: HTTP
09:26:53.632437 IP (tos 0x0, ttl 64, id 53481, offset 0, flags [DF], proto TCP (6), length 52)
localIP.51054 > externalIp.http: Flags [.], cksum 0x92bf (incorrect -> 0x5bcc), ack 464, win 1444, options [nop,nop,TS val 1613152812 ecr 262243674], length 0
09:26:53.638408 IP (tos 0x0, ttl 64, id 2460, offset 0, flags [DF], proto TCP (6), length 11636)
localIP.50892 > externalIp.http: Flags [.], cksum 0xbfff (incorrect -> 0x9468), seq 91408:102992, ack 927, win 1444, options [nop,nop,TS val 1613152814 ecr 262243675], length 11584: HTTP, length: 11584
我看到字段长度有很大差异,而在第一种情况下它非常小,而在后一种情况下它很大并且整个数据传输得非常快。这个长度字段是如何确定的,什么因素影响它?
答案1
观察到的长度差异是由于 TCP 分段卸载造成的。大多数较新的网卡在硬件上都支持此功能,以减少分段数据包时的 CPU 使用率。tcpdump
在分段发生之前观察数据包,因此它看到的数据包比配置的大得多MTU
(线路上的实际数据包仍然受到MTU
大小的限制)
您可以使用 ethtool 验证 NIC 的 tcp 分段卸载(例如,检查 eth0 设备)
# ethtool -k eth0 |grep 'tcp-segmentation-offload'
tcp-segmentation-offload: on
可以使用禁用它ethtool -K tso off
启用 TSO 时看到的传出数据示例(最大达到 64k - TCP 限制)
15:08:22.451667 IP 192.168.230.9.43736 > 192.168.157.102.22: Flags [.], seq 32023713:32088873, ack 19886, win 340, options [nop,nop,TS val 3241810413 ecr 3874669422], length 65160
15:08:22.452203 IP 192.168.230.9.43736 > 192.168.157.102.22: Flags [.], seq 32088873:32154033, ack 19886, win 340, options [nop,nop,TS val 3241810413 ecr 3874669423], length 65160
禁用 TSO 时,长度受 MTU 限制(此处为 1500)
15:09:43.181882 IP 192.168.230.9.43738 > 192.168.157.102.22: Flags [.], seq 9881:11329, ack 4206, win 319, options [nop,nop,TS val 3241830596 ecr 3874750153], length 1448
15:09:43.181886 IP 192.168.230.9.43738 > 192.168.157.102.22: Flags [.], seq 11329:12777, ack 4206, win 319, options [nop,nop,TS val 3241830596 ecr 3874750153], length 1448
有效负载的可变长度取决于 NIC 合并的段数。它可能会根据服务器上当时的 NIC 资源和流量而有所不同。
答案2
The general format of a TCP protocol line is:
src > dst: Flags [tcpflags], seq data-seqno, ack ackno,
win window, urg urgent, options [opts], length len
Src and dst are the source and destination IP addresses and ports.
[...] Len is the length of payload data.
在 TCP 中,有效负载数据以字节表示,(我不是 100% 确定,但在文件中的 tcpdump 源中print-tcp.c
您可以看到,在有关长度字段的注释中仅使用术语字节),并且是 TCP 数据报内的实际数据,即您的应用程序将使用的数据。
Kafka 是一个消息传递应用程序,可能会发送一个字节流,该字节流的带宽随要发送的消息量而变化。
虽然在这种情况下您的数据包没有 TCP 分段,因为我们可以读取标志[DF]
(不分段),但这并不重要。 TCP 数据中的有用数据的lenght
长度为“”字节。
如何选择大小取决于您的 TCP 堆栈(可能是您的操作系统负责)以及它需要发送多少数据。
它有所不同,但这根本不是问题,TCP 足够灵活,当它只需要发送 100 字节时,不会发送 65,365 字节。