多核心Linux内核路径优化的不二法门之——多核心平台TCP优化

前言

本文可以作为《Linux转发性能评估与优化之——转发瓶颈分析与解决方案》的姊妹篇,这两篇文章结合在一起,恰好就是整个Linux内核协议栈的一个优化方案。事实上Linux协议栈本来就是面向两个方向的,一个是转发,更多的是本地接收。目前大量的服务器采用Linux作为其载体,更加体现了协议栈本地处理相对于转发的重要性,因此本文就这个问题扯两句,欢迎拍砖!

1.Linux的TCP实现

1.1.Linux的TCP实现在协议层面分为两个部分

1).连接握手处理

TCP首先会通过三次握手建立一个连接,然后就可以传输数据了。TCP规范并没有指定任何的实现方式,当前的socket规范只是其中一种而已。Linux实现了BSD socket规范。

在Linux中,TCP的连接处理和数据传输处理在代码层面是合并在一起的。

2).数据传输处理

这个so easy,略。

1.2.Linux的TCP在系统架构方面分为两个部分

1).软中断协议栈处理

Linux内核在软中断环境中进行协议栈的处理,在这个处理流程的最上方,会有3个分支:直接将skb复制到用户缓冲区,简单将skb排入到prequeue队列,简单将skb排入backlog队列。

2).用户进程处理

Linux的socket API的处理是在用户进程上下文中进行的。通过1.1节,我们知道由于代码层面上这些都是合并在一起的,因此一个socket会被各种执行流操作,直观的考虑,这需要大量锁的开销。

1.3.连接处理的总体框图

我给出一个连接处理总体框图,其中红线表示发生竞争的地方,而正是这些地方阻止了TCP连接的并行处理,图示如下:

我来一一解释这些红线的意义:

1号红线:

由于用户进程和协议栈操作的是同一个socket,如果用户进程正在copy数据包数据,那么协议栈就要停止同样的操作,反过来也一样,因此需要暂时锁定该socket,然而这种大锁的开销过于大,因此Linux内核协议栈的实现采用了一个更加优雅的方式。

协议栈锁定socket:由于软中断处理协议栈,它可能运行在硬中断之后的任意上下文,因此不能睡眠,故而必须是一把自旋锁slock,由socket本身保有,该锁不仅仅保护和用户进程之间的竞态,也保护不同CPU上对同一个socket协议栈操作之间的竞态(很常见,一个侦听socket上可以同时到达很多连接请求[可悲的是,这些请求不能同时被处理!!)。

用户进程锁定socket:用户进程是可以随时睡眠的,因此可以采用非自旋锁xlock来保护多个进程之间的竞态,然而同时又为了和内核协议栈操作同一个socket的软中断互斥,因此在获取xlock之前,首先要获取该socket的slock,当获取xlock之后或者暂时没有获得xlock要睡眠的时候,将slock释放掉。相关的逻辑如下:

stack_process
{
...
spin_lock(socket->slock); //1
process(skb);
spin_unlock(socket->slock);
...
}


user_process
{
...
spin_lock(socket->slock); //2
while(true)
{
...
spin_unlock(socket->slock);
睡眠;
spin_lock(socket->slock); //2
if (占据xlock成功)
{
break;
}
}
spin_unlock(socket->slock);
...
}

可见,Linux采用了以上的方式很完美的解决了两类问题,第一类问题是操作socket的执行流之间的同步与互斥,第二类问题时软中断上下文和进程上下文之间的锁的不同。

在理解了socket锁定之后,我们来看下backlog这个队列是干什么的。其实很简单,就是将skb推到当前正占据socket的那个进程的一个队列里面,等到进程完成任务,准备释放socket占有权的时候,如果发现该队列里面有skb,那么在其上下文中处理它们。这实际上是一种职责转移,这个转移也可以带来一些优化效果,那就是直接在socket所属的用户进程上下文处理skb,这样就避免了一部分cache刷新。

2号红线

这条线在1号红线的解释中已经涉及了,主要就是上述代码逻辑中的1和2之间的竞争。这个竞争不是最激烈的,本质上它们属于纵向的竞争,一个内核态软中断和一个进程上下文之间的竞争,在同一个CPU上,一般而言,这类竞争的概率很低,因为同一个CPU同时只能执行一个执行流,假设此时它在内核态执行软中断,那么用户态的进程,它一定在睡眠或者被抢占,比如在accept中睡眠。

用户态处理和内核态处理,这种纵向的竞争在单CPU上几乎不会发生,而用户态的xlock根本就是为了解决用户进程之间的竞争,内核通过一个backlog在面对这种竞争时转移了数据包处理职责,事实上在xlock上并不存在竞争,backlog的存在反而带来了一点优化效果。

3号红线(结合3'号红线)

该红线为了解决多个用户进程之间的竞争。之所以画出的是TCP连接处理图而不是数据传输处理图,是因为连接图更能体现问题,在服务器端,一个主进程fork出来N多的子进程或者创建多个线程同时在一个继承下来的socket上accept,这几乎成了服务器设计的准则,那么这多个进程/线程同时到达这个slock的时候,争抢就会很激烈。再看3'号

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值