前面分析Fastsocket慢慢凑成了几篇烂文字,要把一件事情坚持做下来,有时味同爵蜡,但既然选择了,也得硬着头皮做下去。闲话少说,文归正文。本文接自上篇内核模块篇,继续记录学习Fastsocket内核的笔记内容。
Linux kernel 3.9包含TCP/UDP支持多进程、多线程绑定同一个IP和端口的特性,即SO_REUSEPORT
;在内核层面同时也让线程/进程之间各自独享SOCKET,避免CPU核之间以锁资源争夺accept queue
的调用。在fastsocket/kernel/net/sock.h定义sock_common
结构时,可以看到其身影:
unsigned char skc_reuse:4;
unsigned char skc_reuseport:4;
在多个socket.h文件中(比如fastsocket/kernel/include/asm/socket.h),定义了SO_REUSESORT的变量值:
#define SO_REUSEPORT 15
在fastsocket/kernel/net/core/sock.c的sock_setsockopt和sock_getsockopt函数中,都有SO_REUSEPORT
的身影:
sock_setsockopt函数中:
case SO_REUSEADDR:
sk->sk_reuse = valbool;
break;
case SO_REUSEPORT:
sk->sk_reuseport = valbool;
break;
sock_getsockopt函数体中:
case SO_REUSEADDR:
v.val = sk->sk_reuse;
break;
case SO_REUSEPORT:
v.val = sk->sk_reuseport;
break;
在SO_REUSEPORT
特性支持之前的事件驱动驱动服务器资源竞争:
之后呢,可以看做是并行的了:
Fastsocket没有重复发明轮子,在SO_REUSEPORT
基础上进行进一步的优化等。
嗯,后面准备写一个动态链接库小程序,打算让以前的没有硬编码SO_REUSEPORT
的程序也能够在Linux kernel >= 3.9系统上享受真正的端口重用的新特性的支持。
下面按照其架构图所示内核层面从上到下一一列出。
因为Linux Kernel VFS的同步损耗严重
提交记录:
a209dfc vfs: dont chain pipe/anon/socket on superblock s_inodes list
4b93688 fs: improve scalability of pseudo filesystems
对VFS的改进,在所提升的性能中占有超过60%的比例,效果非常明显:
对于多核多接收队列来说,linux原生的协议栈只能listen在一个socket上面,并且所有完成三次握手还没来得及被应用accept的套接字都会放入其附带的accept队列中,accept系统调用必须串行的从队列取出,当并发量较大时多核竞争,这将成为性能瓶颈,影响建立连接处理速度。
Local Listen Table,fastsocket为每一个CPU核克隆监听套接字,并保存到其本地表中,CPU核之间不会存在accept的竞争关系。下面为引用描述内容:
使用流程图概括上面所述:
Linux内核使用一个全局的hash表以及锁操作来维护establised sockets(被用来跟踪连接的sockets)。Fastsocket 想法是把全局table分散到per-Core table,当一个core需要访问socket的时候,只在隶属于自己的table中搜索,因此不需要锁操纵,也不存在资源竞争。由fastsocket建立的socket本地local established table中,其他的regular sockets保存在global的table中。core首先去自己的local table中查找(不需要锁),然后去global中查找。
默认情况下,应用程序主动发包的时候,发出去的包是通过正在执行本进程的那个CPU 核(系统分配的)来完成的;而接收数据包的时CPU 核是由前面提到的RSS或RPS来传递。这样一来,连接可能由不同的两个CPU核来完成。连接应该在本地化处理。RFS和Intel网卡的FlowDirector可以从软件和硬件上缓解这种情况,但是不完备。
RFD(Receive Flow Deliver)主要的思想是CPU核数主动发起连接的时候可以把CPU core的标识和连接的source port编码到一起。CPU cores和ports的关系由一个关系集合来决定【cores,ports】, 对于一个port,有唯一的一个core与之对应。当一个core来建立connection的时候,RFD随机选择一个跟当前core匹配的port。接收包的时候,RFD负责决定这个包应该让哪一个core来处理,如果当前core不是被选中的cpu core,那么就deliver到选中的cpu core。
一般来说,RFD对代理程序收益比较大,单纯的WEB服务器可以选择禁用。
以上参考了大量的外部资料进行整理而成,进而可以获得一个较为整体的Fastsocket内核架构印象。
Fastsocket的努力,在单个TCP连接的管理从网卡触发的硬中断、软中断、三次握手、数据传输、四次挥手等完整的过程在完整在一个CPU核上进行处理,从而实现了每一个CPU核心TCP资源本地化,这样为多核水平扩展打好了基础,减少全局资源竞争,平行化处理连接,同时降低文件锁的副作用,做到了极为高效的短连接处理方案,不得不赞啊。