您会推荐哪些资源(书籍、网页等):
- 解释以太网 TCP/IP 网络中延迟的原因;
- 提及用于查找导致延迟的因素的工具(例如中的某些条目
netstat -s
); - 建议调整 Linux TCP 堆栈以减少 TCP 延迟的方法(Nagle、套接字缓冲区等)。
我所知道的最接近的是这个文件,但相当简短。
或者,欢迎您直接回答上述问题。
编辑需要明确的是,问题不仅仅在于“异常”延迟,还在于一般延迟。此外,它具体涉及以太网上的 TCP/IP,而不是其他协议(即使它们具有更好的延迟特性)。
答案1
关于内核可调的延迟,有一点需要注意:
echo 1 > /proc/sys/net/ipv4/tcp_low_latency
来自文档:
如果设置,TCP 堆栈会做出优先考虑较低延迟而不是较高吞吐量的决定。默认情况下,此选项未设置,这意味着优先考虑较高的吞吐量。应更改此默认值的应用程序示例是 Beowulf 计算集群。默认值:0
您还可以在应用程序中禁用 Nagle 算法(它将缓冲 TCP 输出直到最大段大小),使用以下命令:
#include <sys/types.h>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <linux/tcp.h>
int optval = 1;
int mysock;
void main() {
void errmsg(char *msg) {perror(msg);exit(1);}
if((mysock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
errmsg("setsock failed");
}
if((setsockopt(mysock, SOL_SOCKET, TCP_NODELAY, &optval, sizeof(optval))) < 0) {
errmsg("setsock failed");
}
/* Some more code here ... */
close(mysock);
}
此选项的“反面”是TCP_CORK
,它将“重新 Nagle”数据包。但是请注意, 可能TCP_NODELAY
并不总是按预期执行,并且在某些情况下可能会损害性能。例如,如果您要发送批量数据,则需要最大化每个数据包的吞吐量,因此请设置TCP_CORK
。如果您的应用程序需要立即交互(或者响应比请求大得多,从而抵消开销),请使用TCP _NODELAY
。另一方面,此行为特定于 Linux,BSD 可能有所不同,因此管理员警告。
确保对您的应用程序和基础设施进行彻底的测试。
答案2
根据我的经验,最大的原因是异常在其他方面健康的高速网络上,延迟是 TCP 窗口(RFC1323,第 2 节) 故障,紧随其后的是与 TCP 延迟确认相关的故障(RFC1122 第 4.2.3.2 节)。这两种方法都是对 TCP 的增强,可以更好地处理高速网络。当它们中断时,速度会下降到非常慢的水平。这些情况下的故障会影响大型传输(想想备份流),而极度事务性的小流量(平均数据传输低于 MTU 大小,并且有大量来回)将受这些影响较小。
再次,我发现当两个不同的 TCP/IP 堆栈交互时,这两个问题会变得非常严重。例如 Windows/Linux、2.4-Linux/2.6-Linux、Windows/NetWare、Linux/BSD。类似的东西运行得非常好。微软在 Server 2008 中重写了 Windows TCP/IP 堆栈,这引入了 Server 2003 中不存在的 Linux 互操作性问题(我相信这些问题已经修复,但我不能 100% 确定)。
对于延迟或选择性确认的具体方法存在分歧可能会导致如下情况:
192.168.128.5 -> 192.168.128.20: 1500b 有效载荷,SEQ 1562 192.168.128.5 -> 192.168.128.20: 1500b 有效载荷,SEQ 9524 [200毫秒过去] 192.168.128.20 -> 192.168.128.5:确认 1562 192.168.128.5 -> 192.168.128.20: 1500b 有效载荷,SEQ 12025 192.168.128.5 -> 192.168.128.20: 1500b 有效载荷,SEQ 13824 [200毫秒过去] 192.168.128.20 -> 192.168.128.5:确认 12025
由于所有 200ms 超时(Windows 默认其延迟确认计时器为 200ms),吞吐量降至最低。在这种情况下,对话双方都无法处理 TCP 延迟确认。
TCP 窗口故障更难发现,因为它们的影响可能不太明显。在极端情况下,窗口完全失败,你会得到数据包->确认->数据包->确认->数据包->确认,当传输任何明显大于 10KB 的数据时,速度非常慢,并且会放大任何基本延迟在链路上。更难检测的模式是当双方不断重新协商其窗口大小,而一方(发送方)未能遵守协商,这需要处理一些数据包才能继续传递数据。这种故障在 Wireshark 跟踪中显示为红色闪烁灯,但表现为吞吐量低于预期。
正如我所提到的,上述问题往往会困扰大型传输。它们可能会真正影响诸如流视频或备份流之类的流量,以及下载非常大的文件(如 Linux 发行版 ISO 文件)。事实上,TCP 窗口化被设计为一种解决基本延迟问题的方法,因为它允许数据流水线化;您不必等待发送的每个数据包的往返时间,您只需发送一个大块并等待单个 ACK 即可发送更多数据包。
尽管如此,某些网络模式无法从这些解决方法中获益。事务性强的小额传输(例如数据库生成的传输)最容易受到普通的线路延迟。如果 RTT 很高,这些工作负载将受到很大影响,而大型流工作负载受到的影响则要小得多。
答案3
这个问题有很多答案。
记住 TCP 的工作原理。客户端发送 SYN,服务器应答 SYN/ACK,客户端应答 ACK。服务器收到 ACK 后,就可以发送数据了。这意味着您必须等待 2 倍的往返时间 (RTT) 才能发送第一个有意义的数据。如果您的 RTT 为 500 毫秒,则从一开始您就会有 1 秒的延迟。如果会话持续时间短但数量众多,这将产生很大的延迟。
一旦建立会话,服务器就会发送必须由客户端确认的数据单元。服务器在需要确认第一个数据单元之前只能发送这么多数据。这也会产生延迟。如果数据单元丢失,您必须从那里开始传输,因此会产生额外的延迟。
在 IP 层,存在碎片(尽管现在这种情况很少见)。如果您发送 1501 字节帧,而另一端仅支持 1500 字节的 MTU,那么您将为最后一比特数据发送额外的 IP 数据包。这可以通过使用巨型帧来解决。
提高 TCP/IP 吞吐量的最佳方法是尽可能减少延迟并尽可能避免传输错误。我不知道有任何内核调整,但我相信有人会的。
答案4
这可能不是您想要的答案:WAN 中延迟的主要原因是光速(太慢了!)。此外,沿途带有大缓冲区的饱和链接往往会产生显著的延迟。