LinuxTCP实现优化的背后想法


想象一下当初为什么不让多个进程/线程在一个相同的IP地址和端口上侦听,很简单,这是因为TCP/IP模型将一个端口作为一个四层复用解复用的唯一标识,也就是一个四层地址,正如IP地址属于一个主机一样(属于一块网卡?),一个IP/端口对属于一台主机上一个特定的进程,它只是一个保证唯一性的静态标识。世界上不同的主机不能有相同的IP地址,一台主机上绑定特定IP地址的不同进程也不能有相同的端口,否则就不知道一个流到底该交给哪个进程!
想象一下现在为什么reuseport可以让以前不可能的事变成可能。很简单,在静态因素之外加入了一个动态因素,那就是将发起连接的源IP和源端口也一起考虑了进来,四元组一起做了一个简单的hash计算,所得的结果对Listener数量取模,获取哪个Listener要为这个连接服务。
事实上,我们发现,需要唯一标识的不是一个Listener,而应该是一个连接本身。TCP服务端在有客户端企图建立一个连接时才有意义。那么是什么让一个绑定同一IP/端口的套接字只能Listen一次这么一个限制存在了这么久呢?我认为答案有两个方面,一方面是因为UNIX的进程模型,另一方面是这个限制在单核CPU时代工作的足够好,又可以避免很多问题。

好吧,现在我将Listener和进程完全分割开,我既不赞同绑定同一IP地址/端口的套接字只能Listen一次,又不赞同采用reuseport方案,我暂且忽略了哪个进程/线程在侦听,假设根本没有任何进程/线程侦听的概念,我只求一个连接请求到来的时候,可以成功完成三次握手,创建一个客户socket,而这个很简单,新创建的客户socket被放入一个池中,Listen的任务就完成了,在握手完成之前,与任何进程/线程都无关联,接下来把进程/线程考虑进来,它们来accept,也就是从一个池中获取一个客户socket来处理。事实上,我是分离了Listen和Accept,内核协议栈只负责Listen,而进程/线程只负责Accept,问题就解决了。

杂乱不清的东西纠缠在一起的时候,会引入很多复杂性,避免这些复杂性的方式就是把纠缠在一起的东西剥离,海阔天空。同事为我这个优化取了一个很好的名字,叫做Xsocket,这里的X可以理解成两个意思,一个是“牛X”中的X,一个是“插”!!

相关内容

    暂无相关文章