劣币驱良币的 pacing 之殇

都说 pacing 好 burst 孬(参见:为啥 pacing),就像都知道金币好,掺铁金币孬一样。可现实中掺铁的金币流通性却更好,劣币驱良币。劣币流通性好在卖方希望收到别人的良币而储存,而自己作为买方只使用劣币。

burst 和 pacing 的关系也一样,都希望别人采用 pacing 策略,一旦有人 pacing,自己却 burst 加塞。在高速公路上,都希望别人 200 米车距,自己去加塞。仔细比较这些对弈双方,结论很有趣。

善者假设适用于自主系统,具有同类约定或共识,无罪则无罚,这是不稳定系统,因为一旦有投机者进入系统,假设无罪无罚的善者只能被毒打,而投机假设则适用于几乎所有自组织系统,只有贪婪自私和罪与罚,最后系统收敛到收益和代价之间,这是稳定系统,新来者进入这个系统,最终都会收敛。

我们的世界到处都是活泼开放的投机系统,善者系统反是非常态,死气沉沉。在一个活泼开放的系统中,到处都是投机,试探,收获,遇险,大概都是窦唯《高级动物》里的词,多是贬义,这是劣币之劣,但却是世界的本真。

本文侧重分析 burst 和 pacing 间劣币驱良币的过程。

reno/cubic 的 aimd 行为会被 pacing 改变。aimd + pacing 将形成一个闭环反馈:pacing_rate = cwnd / rtt,等号两边相生。

pacing_rate 达到瓶颈带宽后将稳定下来。增加 cwnd 将带来 queuing delay 等比例增加而维持 pacing_rate 不变,pacing_rate = link_rate 趋于排空 buffer,最终 inflight = pacing_rate * rtt,reno/cubic 等 aimd 流跳出 cwnd limited,cwnd 不再增加。

因此,reno/cubic + pacing 流不再填充 buffer,不再产生 buffer overflow 信号以驱动 aimd。

若有流量退出腾出共享带宽,由于 pacing_rate 和 inflight 相生,没有任何信号触发当前 aimd 流增加 inflight,也就无法 probe 空闲带宽,趋向死寂。

若有新流侵入却不至于丢包的 queuing 情形,本地维护的 cwnd 不变,pacing_rate = cwnd / rtt 由于 rtt 增加而减小意味着发得慢了,进而 inflight 减少,pacing_rate 继续减少。

这表明,根本轮不到 ai 激发 md,背景流作用下,这个闭环反馈自己懂松弛,自动退却。

全链路常规 aimd burst 流量的 buffer overflow 在整个时间序列呈类泊松分布,但无论哪种统计分布,采样次数越多,遭遇 buffer overflow 概率越大,而 pacing 将所有报文在时间序列均匀分布,遭遇 buffer overflow 概率最大,每次都会导致其 cwnd 比例降低,如前述,pacing_rate = cwnd / rtt 这个闭环稳定在 cwnd limited 外,cwnd 在丢包恢复后无法增加。

无论哪种情形,pacing_rate 只能单调递减,趋向跌 0。结论是,pacing 流无法与 aimd 行为相匹配,pacing_rate 与 inflight 相生,阻止 cwnd 的 ai,匡谈 md。

为解决这问题,Linux 引入 net.ipv4.tcp_pacing_ca_ratio 内核参数(即使非 Linux 实现,也必须有类似的措施):

pacing_rate = net.ipv4.tcp_pacing_ca_ratio * (cwnd / rtt)

tcp_pacing_ca_ratio 引入一种 probe 机制,可想而知,它不能比 1 小,甚至不能等于 1,否则 cwnd 将完全无用,但即使大于 1,测量和计算的精度问题以及抖动依然可能将其效果带到 1 以下,pacing_rate 将滑落。默认 1.2,带来非常保守的 probe 效果。

这个 probe 机制以驱动 aimd 运行。但并没解决遭遇 buffer overflow 概率影响 cwnd 增长的问题,增加的 pacing_rate 让 pacing 分布更加密集,遭遇 buffer overflow 概率更大。没有反制拥塞丢包影响的措施,却又完全伸展自己惨烈相迎,自己一直按照 pacing_rate 无 queuing 传输,tcp_pacing_ca_ratio 也只保守 probe,常规的 aimd 退却是对 ai 行为的积累退却,相当于零存整取,但遭遇与自身行为无关(并没有进行有效的 ai)的 buffer overflow 后仍然依照 aimd 原则退就只能一退再退。

谈完 probe 和丢包影响问题,接下来看看被加塞的影响。

pacing 流遭遇 burst 流是个劣币驱良币过程。设带宽为 T,pacing 流连续 2 个报文之间被加塞 n 个 burst 报文,将对 pacing 流引入 (n * 1500) / T 的延时,显然和 burst 量成正比,将引起 inflight 迅速降低而跳出 cwnd limited,这很可怕。换句话说,即使存在 tcp_pacing_ca_ratio probe 参数(即使存在 > 1 的 probe 增益),pacing 流依然很容易跳出 cwnd limited 而进入闭环稳态。

综上,pacing 严重影响 aimd 流的吞吐性能,并使之偏离 aimd 预期行为,不再零存整取而存零整取,取的是代价,更别谈公平收敛,pacing_rate = cwnd / rtt 闭环阻止了自身的 bufferbloat 贡献,pacing 流本身便不会主动(一种忏悔)执行 md(multiplicative-decrease) 收敛动作,被动的 md 纯被欺负。

那么 what about bbr with pacing ?

bbr 自身有状态机驱动 probe 行为,每 8 个 rounds 以 5 / 4 pacing_rate 增益做 probe。但只要是 pacing 流,被 burst 加塞的后果都一样引入 (n * 1500) / T 的延时进而引发 delivery rate 的下滑,被加塞将破坏 bbr 状态机的基本假设以及后续转换,因此 bbr 在一个 window 中不理会实际的测量值,反而坚持该 window 内的 max bandwidth,以此抵抗被动引入的延时,目前这个 window 是 10 rounds。

通过对 reno/cubic,bbr 的 pacing 动力学分析,结合假期最后一天的 高速公路堵车动力学,表明这是个典型的劣币驱良币的 case。无论 reno/cubic 还是 bbr 都需要主动 probe 避免死寂,同时需要某种坚持(persist)缓解被 burst 加塞的伤害,但没有一种良性机制对抗 burst。无奈 pacing 本身就是有价值的松弛策略,面对 burst 被驱逐也是情理之中。

当为传输使能 pacing 时,明明一个好东西,性能却劣化了,大概就是以上原因,网络终究是个劣币驱良币的投机系统。

所以呢,别在 sender host 侧 pacing,pacing 留给网络转发节点做。不 pacing,岂不加重 bufferbloat?但两害相权取其轻,对一厢情愿的 pacing,buffer 不会过分 bloat,我并不是说把 gain * delivery_rate * delivery_interval 全部一次性 burst 出去,可以分多次,定制你自己的 pacing。重要的是,你要知道你在做什么,并知晓后果。

至于数据中心网络,那是另一个故事。rtt 足够小,局域范围,很容易约定并形成大家都遵守的共识,别说 pacing,SDN 可以控制一切,但在广域网,SDN 就不好使,因为 rtt 太长了,反馈周期太久,响应太慢,就不得不接受广域网是一个投机者组成的自组织系统。

皮鞋没有蹬上,露着白袜子。

浙江温州皮鞋湿,下雨进水不会胖。

你可能感兴趣的:(服务器,网络,运维)