TCP 窗口缩放、时间戳和 SACK


TCP 窗口缩放、时间戳和 SACK文章插图
有很多文章出于各种“性能调优”或“安全性”原因 , 建议禁用 TCP 扩展 , 本文提供了这些扩展功能的背景 , 为什么会默认启用 , 它们之间是如何关联的 , 以及为什么通常情况下将它们关闭是个坏主意 。
? 来源:linux.cn ? 作者:Florian Westphal ? 译者:XianLei Gao ?
(本文字数:10601 , 阅读时长大约:16 分钟)
Linux TCP 协议栈具有无数个可以更改其行为的 sysctl 旋钮 。这包括可用于接收或发送操作的内存量、套接字的最大数量、可选的特性和协议扩展 。
有很多文章出于各种“性能调优”或“安全性”原因 , 建议禁用 TCP 扩展 , 比如时间戳或 选择性确认(Selective ACKnowledgments)(SACK) 。
本文提供了这些扩展功能的背景 , 为什么会默认启用 , 它们之间是如何关联的 , 以及为什么通常情况下将它们关闭是个坏主意 。
TCP 窗口缩放TCP 可以承受的数据传输速率受到几个因素的限制 。 其中包括:

  • 往返时间(Round trip time)(RTT) 。 这是数据包到达目的地并返回回复所花费的时间 。 越低越好 。
  • 所涉及的网络路径的最低链路速度 。
  • 丢包频率 。
  • 新数据可用于传输的速度 。 例如 , CPU 需要能够以足够快的速度将数据传递到网络适配器 。 如果 CPU 需要首先加密数据 , 则适配器可能必须等待新数据 。 同样地 , 如果磁盘存储不能足够快地读取数据 , 则磁盘存储可能会成为瓶颈 。
  • TCP 接收窗口的最大可能大小 。 接收窗口决定了 TCP 在必须等待接收方报告接收到该数据之前可以传输多少数据(以字节为单位) 。 这是由接收方宣布的 。 接收方将在读取并确认接收到传入数据时不断更新此值 。 接收窗口的当前值包含在 TCP 报头 中 , 它是 TCP 发送的每个数据段的一部分 。 因此 , 只要发送方接收到来自对等方的确认 , 它就知道当前的接收窗口 。 这意味着往返时间(RTT)越长 , 发送方获得接收窗口更新所需的时间就越长 。
TCP 的未确认(正在传输)数据被限制为最多 64KB 。 在大多数网络场景中 , 这甚至还不足以维持一个像样的数据速率 。 让我们看看一些例子 。
理论数据速率
在往返时间(RTT)为 100 毫秒的情况下 , TCP 每秒最多可以传输 640KB 。 在延迟为 1 秒的情况下 , 最大理论数据速率降至只有 64KB/s 。
这是因为接收窗口的原因 。 一旦发送了 64KB 的数据 , 接收窗口就已经满了 。 发送方必须等待 , 直到对等方通知它应用程序已经读取了至少一部分数据 。
发送的第一个段会把 TCP 窗口缩减去该段的大小 。 在接收窗口值的更新信息可用之前 , 需要往返一次 。 当更新以 1 秒的延迟到达时 , 即使链路有足够的可用带宽 , 也会导致 64KB 的限制 。
为了充分利用一个具有几毫秒延迟的快速网络 , 必须有一个比传统 TCP 支持的窗口更大的窗口 。 “64KB 限制”是协议规范的产物:TCP 头只为接收窗口大小保留了 16 个位 。 这允许接收窗口最大为 64KB 。 在 TCP 协议最初设计时 , 这个大小并没有被视为一个限制 。
不幸的是 , 想通过仅仅更改 TCP 头来支持更大的最大窗口值是不可能的 。 如果这样做就意味着 TCP 的所有实现都必须同时更新 , 否则它们将无法相互理解 。 为了解决这个问题 , 我们改变了对接收窗口值的解释 。
“窗口缩放选项”允许你改变这个解释 , 同时保持与现有实现的兼容性 。
TCP 选项:向后兼容的协议扩展
TCP 支持可选扩展 。 这允许使用新特性增强协议 , 而无需立即更新所有实现 。 当 TCP 发起方连接到对等方时 , 它还会发送一个支持的扩展列表 。 所有扩展都遵循相同的格式:一个唯一的选项号 , 后跟选项的长度以及选项数据本身 。