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. 拥塞检测与响应
拥塞信号:
- 重传超时 (RTO 到期)
- 快速重传 (收到 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 发现过程
-
初始 MTU: 使用保守的初始值 (通常 IPv4 为 576 字节, IPv6 为 1280 字节)
-
探测更大的 MTU:
- 发送设置了 "Don't Fragment" 标志的分组
- 如果成功, 尝试更大的 MTU
- 如果失败 (收到 ICMP "Packet Too Big"), 使用更小的 MTU
-
周期性重新探测: 周期性尝试更大的 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 的拥塞控制设计考虑以下关键因素:
- 多路径支持: 每条路径独立拥塞控制
- TCP 友好性: 与 TCP 公平共享网络带宽
- 多流效率: 在保持拥塞控制的同时避免队头阻塞
- 路径适应: 通过 PMTU 发现优化传输
这些机制确保 SCTP 能够高效利用网络资源, 同时与其他流量公平共存.