pacing 与 burst 趣谈 与 弄巧成拙的 PFC 是我周末写两篇相对宏观的短文,前前后后加了一些句子,太乱,只能单独再写一篇。
当论述 pacing or burst 时,我想说的是系统调度的粒度问题,散开来讲,很多类似的例子都是一个意思。
先看 GRO/LRO 与 pacing,很明显它们是互斥的,pacing 将增加 GRO/LRO 时延,但归根结底还是冲突问题。禁用 GRO/LRO,报文将按照 pacing 频率中断处理器,增加处理开销,每次中断都可看做一次冲突,ingress 报文与系统当前任务间的冲突,类似 CSMA/CD 网络,越 pacing,冲突概率越高,于是类似 Wi-Fi 中的帧聚集技术和协议栈的 GRO/LRO 解的是同一个问题,同样的还有 Big TCP。
所以,最后一跳到底做不做 pacing 就有解了。最后一跳的下一跳是主机,而主机是一个共享处理器资源的密集统计复用系统,与之相比,交换机的统计复用密度要低得多,所以对交换机善 pacing,对主机善 burst。
另一个例子是抢占。和上面例子一样,传统的说法是批处理换吞吐,在响应度和吞吐之间做 tradeoff,但实际还是冲突的调度。
系统正在处理任务时来了一个中断,这就是冲突,处理冲突的方式有三种,后到优先,先到优先,同时退避。第一种结果是高响应度,第二种则是高吞吐,第三种是高公平性。我们随处可见这三种方式,传统服务器一般关抢占,而桌面交互系统则开抢占,前两种方式明显有倾向性,而网络处理侧重公平性,一般在冲突后同时退避,无论 CSMA/CD/CA 网络,还是 buffer 丢包策略。
上面这些例子总结一下,其实说的是统计复用系统的共性,视统计复用密度的不同而用不同策略,策略可以相互转换,这种共性来自于它们可以统一用排队论建模。结论也简单:统计复用系统的指标方差不会为 0,总会遇到最坏情况。遭遇最坏情况的幅度和频率可视为抖动,要通过度量抖动来理解并解决问题。
抖动来自于统计复用系统潜在的非预期的冲突,响应并处理这种冲突带来了系统事件时间戳的不确定性。
这个结论直接影响高速网络的设计。
100M 网络的平均发包间隔时间与操作系统调度周期在一个数量级(调度周期 10ms 量级,发包间隔 0.1ms,虽每次调度周期发送 10 个报文,但每个调度周期可 burst 100 个报文,如 CFS 调度器视 sysctl_sched_latency 而定),系统调度公平性保证了数据包发送的稳定性,但 1000M 网络就需要高精度时钟来驱动了,因为发包间隔在数量级上远小于系统调度周期了。发包间隔越小,抖动对吞吐的影响越大,一根针扎在大象身上没什么感觉,但手一抖就可轻松戳烂一只蚂蚁。
而抖动是统计复用系统固有的,上面那些例子的结论,方差永不可能为 0。
影响高速网络的核心不是某些操作的大时延,而是抖动。即使将访存操作的 100ns 压缩到 0,迟早还是会遭遇几乎无法逾越的抖动墙。
适配高速网络环境有两种途径,要么彻底消除抖动,要么超大带宽吸收掉抖动。彻底消除抖动需要用一个确定性系统替代统计复用系统,而超大带宽需要以低利用率作为代价。
用交通工具类比,高铁相比高速公路算一个确定性系统,而同为统计复用系统,飞机则拥有近乎无限的带宽。
高速公路非常类似目前的 10Gbps 以太网,速度足够快,但不能更快,如果所有司机一起将车速提到 230km,只要有一辆车稍微加速,减速,变道,潜在的灾难性风险非常大,而这完全取决于司机不可预期的行为。
高铁和飞机以不同方式应对超高速度。高铁以确定性调度替代统计性人为操控,而飞机则确保巨大的飞行净空来吸收风力风向,飞行员操控引入的统计波动。
对付任何高速系统的策略无非就是这两样,两种方案都是降低个体不确定性在系统观测尺度下的比重。
那么 400Gbps 网络如何应对,答案也很明显了。要么走确定性网络,消除突发不确定性,要么分配超高带宽,压缩收敛比,增加带宽观测尺度。
确定性网络需要精确分配时间片,而超高带宽需要以最大预期吞吐分配带宽,最大容忍时延分配 buffer,替换以期望吞吐分配带宽,期望方差分配 buffer 的策略。
但无论两种方式中的哪一种,都有资源利用率低的代价,为解决该问题,需要以数据调度为核心取代传输时机调度,换句话说,要合理安排数据的准备时间,以确保最少的空闲时间片碎片,利用虚拟化技术合理调度成块的空闲时间片。即大尺度上数据调度,小尺度上虚拟化,提高资源利用率。
当前人们对高性能网络的重心集中网卡和算法层面,显然很难从根本上解决问题。这种重心体现在,越来越高速的网卡硬件,越来越复杂的 AQM 和拥塞控制算法,所谓各种宣讲的低时延仅针对主机侧处理时延,而不包含网络处理时延,甚至用 PFC 这种技术以增加总时延(合并连累受害流的时延增加)为代价换取主机处理低时延(GBN,AIMD),令人感动。
回到问题的本质,系统调度的不确定性影响超高速网络吞吐,而不确定性可以用一个比值度量,即突发度与总带宽的比值,确定性网络就是减少分子,开发精确调度算法,加大带宽就是扩大分母,消除互相干扰,这又是一个时空 tradeoff,无论哪样总是要花钱的。
说起拥塞控制,前面提到的数据调度可以缓解问题,比如尽量不要让两笔数据同时准备好,简单引入随机因素就能缓解拥塞,但在一个稍大的时间尺度,只要过载,除了增加资源,拥塞不可避免,即使确定性网络,也会引入确定性排队,只是这种排队不需要猜,更容易处理。
另一方面,幸运的是,拥塞具有局部性,这可以从数学上证明,假设同时拥塞,所有节点入度大于出度,与稳定系统守恒矛盾,因此拥塞节点恰是截止拥塞的节点,只要系统中另外的局部仍有空闲资源,至少在理论上,拥塞控制就是可解的。
在算法上,一种可行的方法就是路径调度,这机制我在 2022 年调研过,简单讲就是把拥塞节点绕过去,具体实现上,可以加入排队时间高权重,以此引导路由重收敛,考虑到收敛时间随网络规模的扩展性问题,另一种方法则是直接多路径传输,以最大流,最小割为基础的按路径流排序做权重,做多路径路由,以此确保无论哪里发生拥塞,总会存在备选路径。
当然,第一性原则考虑,解决拥塞问题的方法就是电路交换,看起来有点尴尬,但这才是真本质。
用一些具体问题作为本文最后的内容。解释一些 TCP 的负面问题。
提一个 user socket 与 tcp 的互斥,当某时刻要发送一个报文时,连接被 socket 锁住了,这次发送就会被 delay,如果被系统中其它进程或中断 delay 也是一个结局。设计一个新传输协议时,你容易避开协议问题,但仍要面临实现问题,只能用 buffer 解耦 user 进程和传输控制。如今往网卡里增加复杂逻辑的经理,早晚会把 RDMA 变成 TCP。
另一个问题,TCP 的 ACK 数量具有扩展性问题,在高速网络场景,单位时间内 TCP 报文越多,ACK 越多,而处理短 ACK 需要消耗大量资源,这也是一个冲突处理问题。 之所以会产生这么多 ACK,源自于早期低速网络场景 TCP 过度依赖 ACK self-clock,比如在 RFC2525 中提到的 stretch ack violation,因此 ACK 虽然耗能但不能过度 delay,于是 2 个 full-seg 就会产生一个 ACK。但随着网络带宽的增加,TCP 发送决策更多转向了 sender,甚至有用本地时钟驱动发送的倾向(比如 BBR 及其魔改),但标准难改,ACK 数量正比于吞吐,虽然 GRO/LRO 有效缓解了 ACK 过多,但趋势不变。事实上,合理的做法应该相反,为慢速网络产生过多的 ACK,为高速网络产生较少 ACK,这个思路和 “低速网络对冲突和低性能能耗比更容忍,用 CSMA/CD/CA,高速网络相反,用 buffer 零存整取冲突” 如出一辙,还是那个乘积矩,Data 与 ACK 的乘积维持稳定,这也是设计新协议的建议。
一个车头拉不快,多个动车组一起拉要同步,避免车厢之间裂开或追尾,类似的问题跟高速网络完全一样。
浙江温州皮鞋湿,下雨进水不会胖。