跳到主要内容

7. 拥塞控制

SCTP 使用与 TCP 类似的拥塞控制机制, 以避免网络拥塞并确保网络资源的公平共享.

7.1. SCTP 拥塞控制与 TCP 的差异

虽然 SCTP 的拥塞控制基于 TCP 机制, 但存在以下关键差异:

7.1.1. 多宿主与多路径

SCTP 支持多宿主端点, 每个目的传输地址都维护独立的拥塞控制参数:

  • 按目的地维护的 cwnd: 每条路径都有自己的拥塞窗口
  • 按目的地维护的 ssthresh: 每条路径都有自己的慢启动阈值
  • 按目的地维护的 RTO: 每条路径都有自己的重传超时

这使 SCTP 能够在不同路径上独立执行拥塞控制.

7.1.2. 基于 TSN 的确认

SCTP 使用 TSN 而不是字节序列号进行确认. 这意味着:

  • 拥塞窗口以字节为单位维护
  • SACK 确认 TSN 范围
  • cwnd 更新基于已确认的字节数, 而不是 TSN 数量

7.1.3. 多流传输

SCTP 的多个流共享同一 association 的拥塞控制参数. 流之间没有单独的拥塞控制, 这确保:

  • 所有流公平共享带宽
  • 防止单个流独占资源

7.2. SCTP 慢启动与拥塞避免

SCTP 的拥塞控制算法遵循 TCP 的慢启动和拥塞避免原则.

7.2.1. 初始化与重启

当 association 首次建立, 或某条路径在空闲后重启时:

cwnd = min(4*MTU, max(2*MTU, 4380 bytes))
ssthresh = peer's a_rwnd

: 初始 cwnd 计算确保至少可以发送 2 个完整分组, 但不超过 4 个 MTU 大小的分组.

7.2.2. 慢启动阶段

在慢启动期间 (cwnd <= ssthresh):

收到针对新数据的 SACK 时:

cwnd = cwnd + min(acknowledged bytes, MTU)

规则:

  • cwnd 每次最多增加一个 MTU
  • 仅当所有被确认的数据都是在当前 cwnd 下发送时才增加
  • 当 cwnd 达到或超过 ssthresh 时, 进入拥塞避免阶段

7.2.3. 拥塞避免阶段

cwnd > ssthresh 时:

使用适当字节计数 (ABC):

Per RTT:
partial_bytes_acked = partial_bytes_acked + acknowledged bytes

When partial_bytes_acked >= cwnd:
cwnd = cwnd + MTU
partial_bytes_acked = partial_bytes_acked - cwnd

目标: 每个 RTT 约增加 1 个 MTU 的 cwnd.

7.2.4. 拥塞检测与响应

拥塞信号:

  1. 重传超时 (RTO 到期)
  2. 快速重传 (收到 4 个重复 SACK)

对 RTO 超时的响应:

ssthresh = max(cwnd/2, 4*MTU)
cwnd = 1*MTU
partial_bytes_acked = 0

对快速重传的响应:

ssthresh = max(cwnd/2, 4*MTU)
cwnd = ssthresh
partial_bytes_acked = 0

7.2.5. 空闲期后的处理

如果某个目的地在一个 RTO 周期内没有数据传输 (空闲):

选项 1 (推荐):

cwnd = max(cwnd/2, 4*MTU)

选项 2 (保守):

cwnd = min(4*MTU, max(2*MTU, 4380 bytes))

这可防止在长时间空闲后突然发送大量数据.

7.3. 路径 MTU 发现

SCTP 端点应该使用路径 MTU 发现 (Packetization Layer PMTUD, 如 [RFC4821] 所定义) 来:

  • 确定到目的地可用的最大 MTU
  • 避免 IP 分片
  • 优化数据传输效率

7.3.1. PMTU 发现过程

  1. 初始 MTU: 使用保守的初始值 (通常 IPv4 为 576 字节, IPv6 为 1280 字节)

  2. 探测更大的 MTU:

    • 发送设置了 "Don't Fragment" 标志的分组
    • 如果成功, 尝试更大的 MTU
    • 如果失败 (收到 ICMP "Packet Too Big"), 使用更小的 MTU
  3. 周期性重新探测: 周期性尝试更大的 MTU, 以适应路径变化

7.3.2. MTU 更新对拥塞控制的影响

当 PMTU 增加时:

cwnd = (cwnd / old_MTU) * new_MTU
ssthresh = (ssthresh / old_MTU) * new_MTU

当 PMTU 减小时:

cwnd = (cwnd / old_MTU) * new_MTU
ssthresh = (ssthresh / old_MTU) * new_MTU
partial_bytes_acked = min(partial_bytes_acked, cwnd)

这确保拥塞控制参数与 MTU 大小保持一致关系.

7.3.3. 失败处理

如果 PMTU 发现失败或不可用:

  • 使用保守的 MTU 值
  • 不使用 "Don't Fragment" 标志
  • 允许 IP 层执行分片

总结

SCTP 的拥塞控制设计考虑以下关键因素:

  1. 多路径支持: 每条路径独立拥塞控制
  2. TCP 友好性: 与 TCP 公平共享网络带宽
  3. 多流效率: 在保持拥塞控制的同时避免队头阻塞
  4. 路径适应: 通过 PMTU 发现优化传输

这些机制确保 SCTP 能够高效利用网络资源, 同时与其他流量公平共存.