我没有对我的硬件或内核配置进行任何异常操作(所有默认设置、全新操作系统安装、Linux 内核 3.11 TCP/IP 堆栈),我平均每秒通过 TCP 发送约 383 万条消息,而我的平均值仅为 0.75通过 UDP 每秒发送百万条消息。这似乎完全违背了我对这两个协议的期望。
造成巨大差异的最可能原因是什么?如何在 Ubuntu 13.10 上诊断它?
#TCP RESULTS
Recv Send Send Utilization Service Demand
Socket Socket Message Elapsed Send Recv Send Recv
Size Size Size Time Throughput local remote local remote
bytes bytes bytes secs. 10^6bits/s % S % S us/KB us/KB
87380 65536 64 10.00 1963.43 32.96 17.09 5.500 2.852
#UDP RESULTS
Socket Message Elapsed Messages CPU Service
Size Size Time Okay Errors Throughput Util Demand
bytes bytes secs # # 10^6bits/sec % SS us/KB
4194304 64 10.00 7491010 0 383.5 28.97 24.751
212992 10.00 1404941 71.9 25.03 21.381
对于此测试,我有两台相同的测试服务器,并通过 10G 交叉电缆直接连接。本例中使用的 NIC 是具有开箱即用配置的 Intel X520,连接到主板上的 PCIe 3.0 x8 插槽,通过 NUMA 控制器与 CPU 通信。
答案1
除了没有获得有关测试设置的详细信息之外,主要问题似乎是您使用的消息大小为 64 字节。这与通常的 1500 字节 MTU 相去甚远,并且使 UDP 效率极低:虽然 TCP 将多个发送合并到线路上的单个数据包中(除非设置了 TCP_NODELAY)以有效利用链路,但每个 UDP 消息都会导致一个单独的数据包。从数字上看:大约 23 个 64 字节的消息将被组合成一个 MTU 大小的 TCP 数据包,而对于相同数量的数据,UDP 需要 23 个单个数据包。这些数据包中的每一个都意味着从主机发送、在线传输和对等方接收的开销。从您的案例中可以看出,大约 80% 的 UDP 数据包会丢失,因为您的硬件速度不够快,无法传输和接收所有这些数据包。
所以你可以从这个基准中学到的是:
- UDP 不可靠(80% 丢包)
- 如果数据包大小远低于 MTU,则 UDP 效率低下
- TCP 经过高度优化,可以充分利用链路
至于您的期望,UDP 应该更好:您是否想过为什么所有主要文件传输(ftp、http...)都是使用基于 TCP 的协议完成的?基准测试向您展示了原因。
那么人们为什么要使用 UDP?
- 对于实时数据(例如 IP 语音),您不关心较旧的消息,因此您不希望发送者将消息组合成更大的数据包以有效利用链路。而且您宁愿接受数据包丢失,也不愿让它太晚到达。
- 对于高延迟链路(如卫星),TCP 的默认行为对于有效利用链路来说并不是最佳的。因此,在这种情况下,一些人切换到 UDP,并重新实现 TCP 的可靠性层并针对高延迟链路进行优化,而另一些人则调整现有的 TCP 堆栈以更好地利用链路。
- “丢弃”数据:有时将数据发送出去并且不关心数据包丢失更为重要,例如日志消息(syslog)
- 交互较短:使用 TCP,您需要建立连接并维护状态,这会消耗客户端和服务器的时间和资源。对于简短的交互(例如简短的请求和回复),这可能会带来太大的开销。因此,DNS 通常使用 UDP 完成,但在 UDP 之上构建了重试。