socket与Linux TCP

继续填满长肥管道,接上回:

填满TCP长肥管道

修正了TCP流控rwnd算法后,吞吐就与RTT和rcvbuff解耦了,它的值就是横截面:
在这里插入图片描述
buffer的目的是平滑到达和处理之间的gap而不再作为“要被填满的批量搜集站”,好处至少两点:

  • 解决了rcvbuffer的bufferbloat,就平滑了主机处理延时抖动。
  • 数据读取速率直接取决于CPU而不是rcvbuffer的配置。

但关于这个buffer,又有另一个问题。这个问题可能就是损失那2Gbps(理论25Gbps,实际23Gbps)的祸首。

之前说过,Linux TCP非全双工,socket读写不能(多CPU)并行,ACK和触发发送不能并行,除了这些,软中断Data收和进程socket收也不能并行。

换句话说软中断和socket无法同时将数据放入receive queue和从中取走数据。

无论TCP软中断处理还是socket收,都直接lock或own整个socket,造成软中断和socket进程的串行处理。具体参考Linux内核协议栈的backlog实现。

lock或own整个socket显然粒度太粗,需要lock的只是TCP连接的元数据。

Linux UDP之前也有这个问题,但UDP本身无状态,也就元数据需要保护,针对Linux UDP的优化一气呵成,可参见2019年的一篇文章:

Linux内核UDP收包为什么效率低?能做什么优化?

给出一个UDP双队列优化后的图示:
在这里插入图片描述
Linux TCP也需要类似的双队列buffer,两个队列原子转移,深入细致地管理这个双队列buffer,目的是软中断往buffer放数据的同时,socket可在另一个CPU上从buffer取数据。

这才真正实现TCP协议栈到进程并行流式交接,buffer作为平滑适配器而不是批量搜集站,这是真正的排队系统,socket就像网络中继转发节点,将数据从TCP转交给进程。

如昨天文中所说,进程不一定是最后一站,可能还要落盘,IO库,文件系统,磁盘buffer也依然要如是转交。
话回正途,Linux TCP拆解这个socket lock范围很难,我尝试将receiveve queue独立出来,但socket读也要独立才行,最终失败。

退而求其次,在socket读频率和每次读取的数量之间找一个平衡点。SO_LOWAT正好做这事,但iperf工具不支持该sockopt,可以用LD_PRELOAD来做,也可以用stap:

#!/usr/local/bin/stap -g

%{
#include <net/tcp.h>
%}

function alter_lowat(skk:long)
%{
	struct sock *sk = (struct sock *)STAP_ARG_skk;

	if (inet_sk(sk)->inet_num == 5001 && sk->sk_rcvlowat == 1) {
		sk->sk_rcvlowat = 65500*2;
		STAP_PRINTF("%d\n", sk->sk_rcvlowat);
	}
%}

probe kernel.function("tcp_data_ready")
{
	alter_lowat($sk);
}

意思是buffer里至少攒够了65500*2字节数据后才wakeup进程。保持相同的速率,CPU利用率下降20%。

此外就是调节系统调度器了,我们追求的目标是软中断将n字节放入receive queue和socket从receive queue中读n字节这两件事交替进行,但这几乎做不到:

  • GRO/LRO必须开启,ACK过多会抑制发送。
  • GRO/LRO无法确定数据包长度。
  • Linux软中断无法精确控制pacing。
  • wakeup收包进程无法保证它立即运行。

不过25Gbps尚未touch到CPU瓶颈,若100Gbps打进主机,恐怕上述问题就必须考虑了,由于Linux内核本身是一个复杂的控制面,跑100Gbps注定会吃力,任何wakeup模式因调度延时不确定而不能信任,busy poll模式就更加适合。不过这些都是后话。

终于还是避不开TCP单机性能的损失,核心问题不是调度系统调优,如果真去那般做,可能路子本身就是错的,内核本是一个控制面,内核协议栈跑数据面尚且还好因为尚未touch到CPU瓶颈,但随着带宽持续演进,早晚会touch到CPU瓶颈。作一短文,备忘。

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

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值