实例解析Linux TCP吞吐性能缺陷

前面写了两篇TCP缺陷的作文,一篇关于协议,一篇关于实现:
https://zhuanlan.zhihu.com/p/454523556
https://zhuanlan.zhihu.com/p/457454162
总结一下:

  • 滑动窗口造成HoL阻塞,影响TCP吞吐性能。
  • Linux TCP半双工实现造成ACK流阻滞Data流。

其中的根本原因在于:

  • 协议层面,端到端语义没有和传输逻辑解耦。
  • 实现层面,进程视角和通信视角存在固有矛盾。

我无法印证这些,但很明显这是所有人能感受到的。周中和同事探讨问题,找到了一个case:

  • Intel网卡(10Gbps+)开启rxhash会引起乱序降低吞吐。

原因在下面的论文里:
https://arxiv.org/pdf/1106.0443.pdf
这篇论文印证了我作文里的观点。这里简述一下。

网卡RSS,Flow Director等细节本文不谈,简言之,它们提供了下面的便利:

  • 网卡RX queue和core一一对应,SMP环境下优化并发。
  • RX逻辑和进程被同一个core处理,最优化cache利用率。

进程视角下,RX和TX需要被同一core处理,但传输视角下,RX和TX需要在不同core处理,这就是矛盾。部署服务进程的主机携带的网卡更倾向于进程视角,于是:

  • 同一个五元组标识的Flow映射到同一个core去处理。
    做到以上这点非常容易:
  • TX逻辑中记录Flow->core映射。
  • RX逻辑中根据Flow ID查询core,将处理逻辑路由到该core。

这明显是一个半双工流程。

在进程视角下,作为一个独立实体,进程要么接收数据,要么发送处理,所以在同一core上处理是理所当然的最优解。但在传输视角下,这就是半双工的根源。

在这个半双工框架下,RX core是跟着进程core走的。进程core跳跃了,RX core也会跟着跳跃,这会导致reordering:
实例解析Linux TCP吞吐性能缺陷_第1张图片
如果强制绑core,只能解决reordering的问题,解决不了半双工的问题,我不晓得Intel网卡Flow Director如何禁止让TX逻辑自动记录core并为RX所用,即便能将TX core和RX core各自独立,Linux TCP的RX逻辑和TX逻辑本身的互斥也相当于自废了武功。

所以在继续讨论reordering的危害之前,先总结一下半双工的问题的解决。

论文描述的现象印证了我写的操作系统进程和TCP传输的矛盾,Windows,BSD的实现我没有亲见,但猜测大同小异,这是一个普遍结论,这种架构显然是错误的,正确的做法是:

  • 在数据上做同步,而不是在流程上做同步。
  • 解除socket send/recv互斥和data xmit/ACK rcv互斥。
  • 摒弃进程抽象的独立性,用线程分别处理收和发。
    实例解析Linux TCP吞吐性能缺陷_第2张图片
    现在来看reordering的危害。
    论文结尾处的一句话:

…shows the occurrence of duplicate ACKs, SACKs, and data retransmissions due to packet reordering.

TCP拥塞状态机的所有转换逻辑都围绕着丢包探测和重传展开,具体就是需要不断update scoreboard(即retransmit queue,简称RTX queue)。 reordering的结果有两个:

  • reordering是丢包的信号或者前兆。
  • reordering只是reordering。

显然,无论哪种情况,都会导致吞吐降低,如果发送误判:

  • 根本原因:reordering会阻滞窗口的滑动。
  • 直接后果:窗口不再滑动会阻滞更多数据的发送。
  • 间接后果:retransmit将浪费无效带宽。

reordering本质只是一种end-to-end层面观测到的现象,它不应该和任何end-to-end层面的结论关联在一起。解除滑动窗口和传输逻辑之间的关联,才是正道。矢量窗口仅在end-to-end层面滑动,传输层面只关注标量。这种解耦的约束下,end-to-end观测到的现象将不再影响传输行为:

  • reordering依然阻滞窗口滑动。
  • 但窗口不滑动不影响更多数据的发送。
  • 除非拥塞控制算法判断为拥塞,任何end-to-end现象不会影响发送量。


但在现有TCP的协议以及实现框架下,论文里的case是无解的:

  • 强制绑core,存在send/recv,Data/ACK两个半双工性能问题。
  • 不绑core,自主亲缘性调度,将出现reordering带来的性能问题。

你看,费这么番周折,还解决不了问题,这难道不是协议本身(together with协议的实现)的问题么?

和同事技术讨论,接触到一篇论文,讲了一个很精悍的故事,所以还是那个问题,进程希望同一个core处理收发,进程在core之间乱跳导致发core乱跳,收core就会跟着乱跳,收core乱跳就会乱序,乱序就会降低吞吐,这个闭环妥妥是一个印证我前面两周作文的case啊,不紧不慢,赶紧记录下来,就是本文。

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

你可能感兴趣的:(linux,tcp/ip,运维)