Linux服务端最大并发数是多少?

1. 开场白 在开始今天的文章之前,先抛一个面试题出来: 你接触过的单机最大并发数是多少? 你认为当前正常配置的服务器物理机最大并发数可以到多少? 说说你的理解和分析。 思考几分钟,如果你可以有理有据地说出答案,那确实就不用再往下看了,关上手机去陪陪家人是个不错的选择。 思考几分钟,如果你没有头绪或者对答案不确定,那么你先不用着急关闭页面去玩耍,你应该继续往下看,因为这个问题很不错。 对于后端开发人员来说,并发数往往和技术难度是呈正相关的,实际上也确实如此:体量决定架构。 服务端根据不同业务场景会有不同的侧重点,单纯追求高并发其实并不是根本目的,高可用&稳定性更重要。 所以最终我们的目的是:保证高可用高稳定的基础上追求高并发,降本增效。 高可用&高并发是我们直观感受到的,本质上这是个复杂的系统工程,每个环节都会影响结果,每一块都值得研究和深入。 2. C10K问题和C10M问题 在2000年初的时候,全球互联网的规模并不大,但是当时就已经提出了C10K问题,所谓C10K就是单机1w并发问题,虽然现在不觉得是个难题了,但是这在当初是很有远见和挑战的问题。 C10K问题最早由Dan Kegel发布于其个人站点,原文链接如下: http://www.kegel.com/c10k.html 相关资料显示Dan Kegel目前工作于Google,从1978年起开始接触计算机编程,是Winetricks和Crosstool的作者,大佬年轻时的照片: Dan Kegel这篇文章阅读难度并不大,大白建议从事服务端开发或者对高性能网络开发有兴趣的读者尝试读一读。 在APUE第三版都没有提到epoll,所以我们解决C10K问题的时间并不长,其中IO复用epoll/kqueue/iocp等技术对于C10k问题的解决起到了非常重要的作用。 开源大神们基于epoll/kqueue等开发了诸如libevent/libuv等网络库,从而大幅提高了高并发网络的开发效率,对于C/C++程序员来说并不陌生。 这里简单提一下针对下一个10年的展望和挑战:C10M问题。 站在浪尖的那一批人早就开始思考让单机达到1000w并发,现在听起来感觉不可思议,但是要达到这个目标,除了硬件上的提升,更重要的是对系统软件和协议栈的改造。 Errata Security的CEO Robert Graham在Shmoocon 2013大会上的演讲,大佬重要的观点是: 不要让OS内核执行所有繁重的任务:将数据包处理、内存管理、处理器调度等任务从内核转移到应用程序高效地完成,让诸如Linux这样的OS只处理控制层,数据层完全交给应用程序来处理。 确实也是如此,难道你不觉得Linux内核做了太多不该自己做的事情了吗? 近几年出现的DPDK、PFRING、NETMAP等技术也是类似的思想,现在流行的协处理器+CPU的架构也是这样的: 3. 服务器最大并发数分析 前面提到的C10K和C10M问题都是围绕着提升服务器并发能力展开的,但是难免要问:服务器最大的并发上限是多少? 3.1 五元组 做过通信的盆友们一定听过五元组这个概念,一个五元组可以唯一标记一个网络连接,所以要理解和分析最大并发数,就必须理解五元组: 这样的话,就可以基本认为:理论最大并发数 = 服务端唯一五元组数。 3.2 端口&IP组合数 那么对于服务器来说,服务端唯一五元组数最大是多少呢? 有人说是65535,显然不是,但是之所以会有这类答案是因为当前Linux的端口号是2字节大小的short类型,总计2^16个端口,除去一些系统占用的端口,可用端口确实只剩下64000多了。 对于服务端本身来说,DestPort数量确实有限,假定有多张网卡,每个网卡绑定多个IP,服务端的Port端口数和IP数的组合类型也是有限的。 对于客户端来说,本身的端口和IP也是一样有限的,虽然这是个组合问题,但是数量还是有限的: 3.3 并发数理论极限 看了前面的端口&IP的组合数计算,好像并发数并不会特别大。 错了,是真的会很大。 分析一下,前面的计算都是针对单个服务器或者客户端的,但是实际上每个服务器会应对全网的所有客户端,那么从服务端看,源IP和源Port的数量是非常大的。 理论上服务端可以接受的客户端IP是2^32(按照IPv4计算),端口数是2^16,目前端口号仍然是16bit的,所有这个理论最大值是2^48,果然很大!… Continue reading Linux服务端最大并发数是多少?

Published
Categorized as 网络

万字长文|全(小区局域)网最强TCP/IP拥塞控制总结…

一.先唠唠嗑 按照计划,今天该出分布式一致性系列的第四篇-Paxos算法,但是又鸽了。 Paxos这个算法要很好地表达写出来并不容易,所以到现在还没有完成,于是就有了这篇组装的带有丝丝标题党感觉的干货文章,全小区最强TCP/IP总结…逃… 在正式开始文章技术点之前,想先聊一下我对面试中的TCP/IP问题的一些拙见,希望对盆友们有所帮助。 在招聘岗位描述中,几乎必然有一条熟悉、掌握、精通TCP/IP协议、Http协议、网络编程技术。 对于我们求职者来说,肯定知道的越多越好,但是就像过日子一样钱要花在刀刃上,准备面试也是一样的,我们该怎么准备这部分呢? 我个人认为合理的优先级排序是:网络编程技术 > Http协议 > TCP/IP协议热点问题 > TCP/IP协议普通问题。 从面试官的角度来说,面试中还是要注重实战,问一些边边角角的细节或者自己平时遇到的奇怪问题,并不能探测出侯选人的边界,反而让侯选人觉得这个面试官抓不住重点。 有时候遇到一些侯选人说自己哪块掌握的比较好,那可以交流一下,比如之前遇到侯选人说自己读过Redis源码,顿时让我很有兴趣,简单了解了对方阅读的版本之后,就开始切磋,很快就可以探测出侯选人的所说的Redis源码边界。 回到网络这块,C/C++的话轮子比较少,有时候需要自己搞一个Socket写个小型的服务端或者客户端,像Python/Go这些语言做的已经非常好了,可能不到5行一个简单的echo服务就跑起来了。因为之前自己是写C++服务端的,回忆起第一次用Python的Tornado框架写服务,着实被惊艳了,开发速度着实很快,性能也很不错。 说这个的目的在于,如果对于时间紧任务重的求职者就不要胡子眉毛一把抓,抓几个重点问题好好理解一下就可以了,如果真遇到问边角问题的面试,那也不必懊恼,可能大概率以后共事脑回路也不一样,还是相忘于江湖比较好。 在掌握一些重点问题的面试套路和回答之后,还是建议去深入了解一些这些技术细节,更多的是去培养和锻炼我们思考问题的方法和意识,之前在知乎就有这样的问题,就像研究往年的高考题一样,我们去思考TCP/IP在发展过程中的问题以及解决方案,并且当前存在的瓶颈作出自己的判断和思考,都是很有益的。 我想这也是打开TCP/IP的正确方式吧:实战派和训练思维派。 今天和大家一起学习下TCP/IP中的热点问题:拥塞控制。本文本着实战和思维训练兼顾的原则将从以下几个方面展开: 拥塞控制的算法策略分类 拥塞控制出现的意义和目的 实现拥塞控制的几种算法和侧重点 拥塞控制的主要过程和关键点 BBR算法的一些原理和思路 2. 我和TCP/IP协议 我在5年前研究生刚毕业的时候,在一家做深度包检测DPI的公司待了差不多两年,可能读者要问啥是深度包检测? 简单提一下哈,深度包检测 DPI (Deep Packet Inspection)就是识别TCP/IP网络协议中各种各样的报文,来进行流量管控和分析,在网络安全领域应用很多,属于通信&互联网领域的交叉业务。 整个DPI系统是非常复杂的,目前业界有硬件DPI和软件DPI两种主流类型,硬件的吞吐量大造价也高,软件的比较灵活成本也相对低廉。 当时每天的工作就是抓包分析、用C++写业务插件来处理各种丢包/乱序/重传问题等等,有时候业务需要还要单独开发wireshark的插件来解析自定义的报文。 现在看看这份工作开启了我和TCP/IP协议网络的友谊之门。 在刚毕业前3年换工作的时候,几乎总会被问到TCP/IP协议的一些东西,碰到一些专业人士问的就比较深入,好在近两年的经验让这些问题基本都在射程之内。 所以经历都是财富,好好学一下,说不准哪天就派上用场了呢。 三. 走心推荐 TCP/IP协议是一个协议族,如果真的非常感兴趣或者工作需要建议直接卷一卷二卷三,但是对于大多数读者来说,应付面试或者平时排查问题掌握一些重点内容也就够了。 TCP/IP详解的三本书译文难免失真,有决心和兴趣的同学可以搞几本英文原版的,这是豆瓣读书上的一些评分: 四.聊聊拥塞控制算法 我们知道TCP/IP协议栈是一个简化的分层模型,是互联网世界连接一切的基石,一起来看一张七层模型vs四层模型的简图: 看到一篇文章说到TCP拥塞控制算法并不是简单的计算机网络的概念,也属于控制论范畴,感觉这个观点很道理。 TCP拥塞控制算法的目的可以简单概括为:公平竞争、充分利用网络带宽、降低网络延时、优化用户体验,然而就目前而言要实现这些目标就难免有权衡和取舍。 但是现在的网络通信基础设施水平一直在飞速提高,相信在未来的某个时间点这些目标都可以达到,小孩子才选择,我们大人全都要! 算法演进 在理解拥塞控制算法之前我们需要明确一个核心的思想:闻道有先后 术业有专攻,笔者觉得这是一个非常重要的共识问题,把A踩在泥土里,把B吹捧到天上去,都不是很好的做法。 实际的网络环境十分复杂并且变化很快,并没有哪个拥塞控制算法可以全部搞定,每一种算法都有自己的特定和适用领域,每种算法都是对几个关键点的权衡,在无法兼得的条件下有的算法选择带宽利用率,有的算法选择通信延时等等。 在明确这个共识问题之后,我们对待各个拥塞控制算法的态度要平和一些,不要偏激地认为谁就是最好,几十年前的网络状况和现在是截然不同的,我们永远都是站在巨人的肩膀之上的,这也是科学和文明进步的推动力。 算法分类 传统拥塞控制算法并不是一蹴而就的,复杂的网络环境和用户的高要求推动着拥塞控制算法的优化和迭代,我们看下基于丢包策略的传统拥塞控制算法的几个迭代版本,如图所示: 与此同时还有一类算法是基于RTT延时策略来进行控制的,但是这类算法在发包速率上可能不够激进,竞争性能不如其他算法,因此在共享网络带宽时有失公平性,但是算法速率曲线却是很平滑。… Continue reading 万字长文|全(小区局域)网最强TCP/IP拥塞控制总结…

Published
Categorized as 网络

36 张图详解 DNS :网络世界的导航

上帝视角 我们平时在访问网站时,不使用 IP 地址,而是网站域名。但是抓包发现:交互报文是以 IP 地址进行的。那么 IP 地址是从哪来的呢?这是因为 DNS 把网站域名自动转换为 IP 地址。 报文交互抓包 DNS 出现 TCP/IP 是基于 IP 地址进行通信的,但是 IP 地址不太好记。于是出现了另一种方便记忆的标识符,那就是主机名。为计算机配置主机名,在进行网络通信时,直接使用主机名,而不用输入一大串的 IP 地址。同时,系统通过一个叫 hosts 的文件,实现主机名转换 IP 地址的功能。hosts 文件包括主机名和 IP 地址的对应关系。当需要通过主机名访问主机时,它就会查看本地的 hosts 文件,从文件中找到相对应的 IP 地址,然后进行报文发送。如果在 hosts 文件中没找到相关信息,则主机访问失败。 hosts 文件是主机的本地文件,优点是查找响应速度快。它主要用来存储一些本地网络的主机名和 IP 地址的对应信息。这样,主机在以主机名访问本地网络主机时,通过 hosts 文件可以迅速获得相应的 IP 地址。 hosts文件 每台主机的 hosts 文件都需要单独手工更新。随着网络规模的不断扩大、接入计算机的数量不断增加,维护难度越来越大,每台主机同步更新,几乎是一件不可能完成的任务。 hosts维护难 为了解决 hosts 文件维护困难的问题,出现了 DNS 域名系统,一个可以解决主机名和 IP 地址互相转换的系统。无论网络规模变得多么庞大,都能在一个小范围内通过 DNS 进行管理。 DNS域名系统 DNS 介绍… Continue reading 36 张图详解 DNS :网络世界的导航

图解 | 为嘛有 TCP 粘包和拆包

事情从一个健身教练说起吧。 李东,自称亚健康终结者,尝试使用互联网+的模式拓展自己的业务。在某款新开发的聊天软件琛琛上发布广告。 键盘说来就来。疯狂发送”李东”,回车发送!,”亚健康终结者”,再回车发送! 还记得四层网络协议长什么样子吗? 四层网络协议 四层网络模型每层各司其职,消息在进入每一层时都会多加一个报头,每多一个报头可以理解为数据报多戴一顶帽子。这个报头上面记录着消息从哪来,到哪去,以及消息多长等信息。比如,mac头部记录的是硬件的唯一地址,IP头记录的是从哪来和到哪去,传输层头记录到是到达目的主机后具体去哪个进程。 在从消息发到网络的时候给消息带上报头,消息和纷繁复杂的网络中通过这些信息在路由器间流转,最后到达目的机器上,接受者再通过这些报头,一步一步还原出发送者最原始要发送的消息。 四层网络协议 (1) 为什么要将数据切片 软件琛琛是属于应用层上的。 而”李东”,”亚健康终结者”这两条消息在进入传输层时使用的是传输层上的 TCP 协议。消息在进入传输层(TCP)时会被切片为一个个数据包。这个数据包的长度是MSS。 可以把网络比喻为一个水管,是有一定的粗细的,这个粗细由网络接口层(数据链路层)提供给网络层,一般认为是的MTU(1500),直接传入整个消息,会超过水管的最大承受范围,那么,就需要进行切片,成为一个个数据包,这样消息才能正常通过“水管”。 数据分片 MTU 和 MSS 有什么区别 MSS和MTU的区别 MTU: Maximum Transmit Unit,最大传输单元。 由网络接口层(数据链路层)提供给网络层最大一次传输数据的大小;一般 MTU=1500 Byte。 假设IP层有 <= 1500 byte 需要发送,只需要一个 IP 包就可以完成发送任务;假设 IP 层有> 1500 byte 数据需要发送,需要分片才能完成发送,分片后的 IP Header ID 相同。 MSS:Maximum Segment Size 。TCP 提交给 IP 层最大分段大小,不包含 TCP Header 和  TCP Option,只包含… Continue reading 图解 | 为嘛有 TCP 粘包和拆包

Published
Categorized as 网络

面试必备!TCP协议经典十五连问!

前言 TCP协议是大厂面试必问的知识点。整理了15道非常经典的TCP面试题,希望大家都找到理想的offer呀 公众号:捡田螺的小男孩 1.  讲下TCP三次握手流程 开始客户端和服务器都处于CLOSED状态,然后服务端开始监听某个端口,进入LISTEN状态 第一次握手(SYN=1, seq=x),发送完毕后,客户端进入 SYN_SEND 状态 第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1), 发送完毕后,服务器端进入 SYN_RCVD 状态。 第三次握手(ACK=1,ACKnum=y+1),发送完毕后,客户端进入 ESTABLISHED 状态,当服务器端接收到这个包时,也进入 ESTABLISHED 状态,TCP 握手,即可以开始数据传输。 2.TCP握手为什么是三次,不能是两次?不能是四次? TCP握手为什么是三次呢?为了方便理解,我们以谈恋爱为例子:两个人能走到一起,最重要的事情就是相爱,就是我爱你,并且我知道,你也爱我,接下来我们以此来模拟三次握手的过程: 为什么握手不能是两次呢? 如果只有两次握手,女孩子可能就不知道,她的那句我也爱你,男孩子是否收到,恋爱关系就不能愉快展开。 为什么握手不能是四次呢? 因为握手不能是四次呢?因为三次已经够了,三次已经能让双方都知道:你爱我,我也爱你。而四次就多余了。 3. 讲下TCP四次挥手过程 第一次挥手(FIN=1,seq=u),发送完毕后,客户端进入FIN_WAIT_1 状态 第二次挥手(ACK=1,ack=u+1,seq =v),发送完毕后,服务器端进入CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态 第三次挥手(FIN=1,ACK1,seq=w,ack=u+1),发送完毕后,服务器端进入LAST_ACK 状态,等待来自客户端的最后一个ACK。 第四次挥手(ACK=1,seq=u+1,ack=w+1),客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT状态,等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入 CLOSED 状态。服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。 4. TCP挥手为什么需要四次呢? 举个例子吧! ★… Continue reading 面试必备!TCP协议经典十五连问!

Linux 篇: Epoll 实现的多路复用为什么这么快?

坚持思考,就会很酷 在 Linux 系统之中有一个核心武器:epoll 池,在高并发的,高吞吐的 IO 系统中常常见到 epoll 的身影。 IO 多路复用   在 Go 里最核心的是 Goroutine ,也就是所谓的协程,协程最妙的一个实现就是异步的代码长的跟同步代码一样。比如在 Go 中,网络 IO 的 read,write 看似都是同步代码,其实底下都是异步调用,一般流程是: write ( /* IO 参数 */ )     请求入队     等待完成       后台 loop 程序     发送网络请求     唤醒业务方 Go 配合协程在网络 IO 上实现了异步流程的代码同步化。核心就是用 epoll 池来管理网络 fd 。 实现形式上,后台的程序只需要 1 个就可以负责管理多个 fd 句柄,负责应对所有的业务方的 IO 请求。这种一对多的 IO 模式我们就叫做 IO 多路复用。 多路是指?多个业务方(句柄)并发下来的 IO 。 复用是指?复用这一个后台处理程序。 站在 IO… Continue reading Linux 篇: Epoll 实现的多路复用为什么这么快?

TCP连接中客户端的端口号是如何确定的?

大家好,我是飞哥! 在 TCP 连接中,客户端在发起连接请求前会先确定一个客户端端口,然后用这个端口去和服务器端进行握手建立连接。那么在 Linux 上,客户端的端口到底是如何被确定下来的呢? 事实上很多我们平时遇到的问题都和这个端口选择过程相关,如果能深度理解这个过程,将有助于我们对这些问题的深刻理解。 Cannot assign requested address 报错是怎么回事? 一个客户端端口可以同时用在两条 TCP 连接上吗? 还是让我们借助一段简单到只有两句的代码,从这个来讲起! int main(){  fd = socket(AF_INET,SOCK_STREAM, 0);  connect(fd, …);  … } 一、创建 socket 客户端在发起连接的时候,需要事先创建一个 socket。在 c 语言中,就是调用 socket 函数,例如 socket(AF_INET,SOCK_STREAM, 0) 这句。 socket 函数执行完毕后,在用户层视角我们是看到返回了一个文件描述符 fd。但在内核中其实是一套内核对象组合,大体结构如下。 从上图我们看到,socket 在内核里并不是一个内核对象。而是包含 file、socket、sock 等多个相关内核对象构成,每个内核对象还定义了 ops 操作函数集合。在后面的内核源码执行过程中,我们需要时不时回头来看这些内核对象,这里先简单了解一下就行。 这些内核对象都是在 socket 系统调用执行过程中创建出来的。为了避免喧宾夺主,这里只列出入口代码,详细过程就不展开介绍了。 //file: net/socket.c SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) {  //创建 socket、sock 等内核对象,并初始化  sock_create(family, type, protocol, &sock);  //创建 file 内核对象,申请 fd  sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));  …… } 二、connect 发起连接… Continue reading TCP连接中客户端的端口号是如何确定的?

Published
Categorized as 网络

为什么服务端程序都需要先 listen 一下?

大家好,我是飞哥。飞哥在北京摇号 9 年多,最近终于算是搞下来个北京的电动车牌,其中的艰难过程写个一万字估计都写不完。不管咋说,新能源也是车,总算是有车能开了。这几天买车卖车(外地牌)忙的团团转。不过无论多忙,硬核文章仍然不能停! 大家都知道,在创建一个服务器程序的时候,需要先 listen 一下,然后才能接收客户端的请求。例如下面的这段代码我们再熟悉不过了。 int main(int argc, char const *argv[]) {  int fd = socket(AF_INET, SOCK_STREAM, 0);  bind(fd, …);  listen(fd, 128);  accept(fd, …); 那么我们今天来思考一个问题,为什么需要 listen 一下才能接收连接?或者换句话说,listen 内部执行的时候到底干了啥? 如果你也想搞清楚 listen 内部的这些秘密,那么请跟我来! 一、创建 socket 服务器要做的第一件事就是先创建一个 socket。具体就是通过调用 socket 函数。当 socket 函数执行完毕后,在用户层视角我们是看到返回了一个文件描述符 fd。但在内核中其实是一套内核对象组合,大体结构如下。 这里简单了解这个结构就行,后面我们在源码中看到函数指针调用的时候需要回头再来看它。 二、内核执行 listen 2.1 listen 系统调用 我在 net/socket.c 下找到了 listen 系统调用的源码。 //file: net/socket.c SYSCALL_DEFINE2(listen, int, fd, int, backlog) {  //根据 fd 查找 socket 内核对象  sock = sockfd_lookup_light(fd, &err, &fput_needed);  if (sock) {   //获取内核参数 net.core.somaxconn   somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn;   if ((unsigned int)backlog > somaxconn)    backlog = somaxconn;      //调用协议栈注册的 listen 函数   err = sock->ops->listen(sock, backlog);   …… } 用户态的… Continue reading 为什么服务端程序都需要先 listen 一下?

Published
Categorized as 网络

深入解析常见三次握手异常

大家好,我是飞哥! 在后端接口性能指标中一类重要的指标就是接口耗时。具体包括平均响应时间 TP90、TP99 耗时值等。这些值越低越好,一般来说是几毫秒,或者是几十毫秒。如果响应时间一旦过长,比如超过了 1 秒,在用户侧就能感觉到非常明显的卡顿。如果长此以往,用户可能就直接用脚投票,卸载我们的 App 了。 在正常情况下一次 TCP 连接耗时也就大约是一次 RTT 多一点。但事情不一定总是这么美好,总会有意外发生。在某些情况下,可能会导致连接耗时上涨、CPU 处理开销增加、甚至是超时失败。 今天飞哥就来说一下我在线上遇到过的那些 TCP 握手相关的各种异常情况。 一、客户端 connect 异常 端口号和 CPU 消耗这二者听起来感觉没啥太大联系。但我却遭遇过因为端口号不足导致 CPU 消耗大幅上涨的情况。来听飞哥分析分析为啥会出现这种问题! 客户端在发起 connect 系统调用的时候,主要工作就是端口选择(参见TCP连接中客户端的端口号是如何确定的?)。 在选择的过程中,有个大循环,从 ip_local_port_range 的一个随机位置开始把这个范围遍历一遍,找到可用端口则退出循环。如果端口很充足,那么循环只需要执行少数几次就可以退出。但假设说端口消耗掉很多已经不充足,或者干脆就没有可用的了。那么这个循环就得执行很多遍。我们来看下详细的代码。 //file:net/ipv4/inet_hashtables.c int __inet_hash_connect(…) {  inet_get_local_port_range(&low, &high);  remaining = (high – low) + 1;  for (i = 1; i <= remaining; i++) {   // 其中 offset 是一个随机数   port = low + (i + offset) % remaining;   head = &hinfo->bhash[inet_bhashfn(net, port,      hinfo->bhash_size)];   //加锁   spin_lock(&head->lock);    //一大段的选择端口逻辑   //……   //选择成功就 goto ok   //不成功就 goto next_port   next_port:    //解锁    spin_unlock(&head->lock);   } } 在每次的循环内部需要等待锁,以及在哈希表中执行多次的搜索。注意这里的是自旋锁,是一种非阻塞的锁,如果资源被占用,进程并不会被挂起,而是会占用 CPU 去不断尝试获取锁。… Continue reading 深入解析常见三次握手异常

Published
Categorized as 网络

漫画 | 一台Linux服务器最多能支撑多少个TCP连接?

困惑很多人的并发问题 在网络开发中,我发现有很多同学对一个基础问题始终是没有彻底搞明白。那就是一台服务器最大究竟能支持多少个网络连接?我想我有必要单独发一篇文章来好好说一下这个问题。 很多同学看到这个问题的第一反应是65535。原因是:“听说端口号最多有65535个,那长连接就最多保持65535个了”。是这样的吗?还有的人说:“应该受TCP连接里四元组的空间大小限制,算起来是200多万亿个!” 如果你对这个问题也是理解的不够彻底,那么今天讲个故事讲给你听! 一次关于服务器端并发的聊天 “TCP连接四元组是源IP地址、源端口、目的IP地址和目的端口。任意一个元素发生了改变,那么就代表的是一条完全不同的连接了。拿我的Nginx举例,它的端口是固定使用80。另外我的IP也是固定的,这样目的IP地址、目的端口都是固定的。剩下源IP地址、源端口是可变的。所以理论上我的Nginx上最多可以建立2的32次方(ip数)×2的16次方(port数)个连接。这是两百多万亿的一个大数字!!” “进程每打开一个文件(linux下一切皆文件,包括socket),都会消耗一定的内存资源。如果有不怀好心的人启动一个进程来无限的创建和打开新的文件,会让服务器崩溃。所以linux系统出于安全角度的考虑,在多个位置都限制了可打开的文件描述符的数量,包括系统级、用户级、进程级。这三个限制的含义和修改方式如下:” 系统级:当前系统可打开的最大数量,通过fs.file-max参数可修改 用户级:指定用户可打开的最大数量,修改/etc/security/limits.conf 进程级:单个进程可打开的最大数量,通过fs.nr_open参数可修改 “我的接收缓存区大小是可以配置的,通过sysctl命令就可以查看。” $ sysctl -a | grep rmem net.ipv4.tcp_rmem = 4096 87380 8388608 net.core.rmem_default = 212992 net.core.rmem_max = 8388608 “其中在tcp_rmem”中的第一个值是为你们的TCP连接所需分配的最少字节数。该值默认是4K,最大的话8MB之多。也就是说你们有数据发送的时候我需要至少为对应的socket再分配4K内存,甚至可能更大。” “TCP分配发送缓存区的大小受参数net.ipv4.tcp_wmem配置影响。” $ sysctl -a | grep wmem net.ipv4.tcp_wmem = 4096 65536 8388608 net.core.wmem_default = 212992 net.core.wmem_max = 8388608 “在net.ipv4.tcp_wmem”中的第一个值是发送缓存区的最小值,默认也是4K。当然了如果数据很大的话,该缓存区实际分配的也会比默认值大。” 服务端百万连接达成记 “准备啥呢,还记得前面说过Linux对最大文件对象数量有限制,所以要想完成这个实验,得在用户级、系统级、进程级等位置把这个上限加大。我们实验目的是100W,这里都设置成110W,这个很重要!因为得保证做实验的时候其它基础命令例如ps,vi等是可用的。“ 活动连接数量确实达到了100W: $ ss -n | grep ESTAB | wc -l   1000024 当前机器内存总共是3.9GB,其中内核Slab占用了3.2GB之多。MemFree和Buffers加起来也只剩下100多MB了: $ cat /proc/meminfo MemTotal:        3922956 kB MemFree:           96652 kB MemAvailable:       6448 kB Buffers:           44396 kB …… Slab:          3241244KB kB 通过slabtop命令可以查看到densty、flip、sock_inode_cache、TCP四个内核对象都分别有100W个: 结语 互联网后端的业务特点之一就是高并发. 但是一台服务器最大究竟能支持多少个TCP连接,这个问题似乎却又在困惑着很多同学。希望今天过后,你能够将这个问题踩在脚下摩擦! 学习是一件痛苦的事情,尤其咱们号里很多读者朋友都是工作满一天了再来看我的技术号的文章的。我一直都在琢磨到底怎么样组织技术内容形式,能让大家理解起来更能省一点脑细胞呢。这篇服务器的最大并发数的文章是早就想发的,但是写了两三个版本都不满意。今天终于想出了一种让大家更容易理解的方式,算过了自己这关了。 如果您喜欢我的文章、并觉得它有用,期望您能不吝把它转发到你的朋友圈,技术群。或者哪怕是点个赞,点个再看都可以。触达更多的技术同学并收获大家的反馈将极大地提升彦飞的创作动力! 改天再讲客户端,敬请期待!! 开发内功修炼 飞哥有鹅厂、搜狗 10 年多的开发工作经验。通过本号,我把多年中对于性能的一些深度思考分享给大家。 66篇原创内容 公众号  

Published
Categorized as 网络