当前位置: 首页 > Linux

一台机器最多支持多少个TCP连接?今天就知道了!

时间:2023-04-06 19:32:50 Linux

在网络开发中,我发现很多同学从来没有完全理解一个基础问题。即一台机器可以支持多少个网络连接?我想我需要单独发一篇文章来谈谈这个问题。很多同学看到这道题的第一反应是65535,原因是:“听说最多有65535个端口号,所以长连接最大为65535”。是这样吗?有人说应该是受限于TCP连接中四元组的空间大小,所以是一个非常非常大的数字。两个答案都是正确的,也都不是正确的。其实,要想弄清楚这个问题,最重要的是要分清TCP连接两端的角色——客户端和服务端。您手头上的任何服务器通常既是服务器又是客户端。比如你开发的后台接口,你就是用户的服务端。但是你要请求Redis和Mysql去获取数据,这时候又变成了client。如果你不把本机理解为客户端和服务器,你总会被这个问题搞糊涂的。因此,本文分别从客户端和服务器端进行讨论。客户端现在我们单独谈谈客户端。当一台机器作为客户端时,它能支持多少个TCP连接?说什么都没意义,直接用代码试试吧。1、开始实验前,我们先查看一下手头机器的端口数配置。$sysctl-a|grepip_local_port_rangenet.ipv4.ip_local_port_range=1500065000通过以上内核参数的输出,我们可以看到内核已经开放了50000个端口。用于TCP连接。接下来是一段看起来很长其实很简单的TCP客户端连接的代码。使用它连接到任何TCP服务器,例如Nginx和Redis。我用这段代码在我的一台机器上发起了一个Nginx的连接$phpclient1.php某服务器IP80通过netstat命令看到连接数稳步上升,但是升到5W的时候就出现了错误socket_connect()失败的原因是:Cannotassignrequestedaddress回头看我们的ip_local_port_range参数值,只有5000065000-15000是开放的。事实上,已经超过了这个限制。这个时候,我们似乎可以得出一个初步的结论。Linux作为客户端建立连接时,最大连接数受内核参数net.ipv4.ip_local_port_range限制,ip_local_port_range是可配置的。最大理论范围为0-65535。杰,如果你此时相信我的结论,你又要被我引到沟里了。为什么这么说,让我们看看下面的实验。首先通过ifconfig命令可以看到我的机器上有两块网卡,每块网卡都配置了一个ip。然后我们修改第一个实验的代码,允许在发起连接前使用socket_bind绑定ip。接下来,我们分别启动两个控制台,分别执行代码。其中10.143.x.x和10.153.x.x是实验机的两个网卡IP。$phpclient1.php10.143.x.x某服务器IP80$phpclient2.php10.153.x.x某服务器IP80此时通过ss命令监听本机的ESTABLISH连接,发现已经超出50,000并且正在接近100,000。$ss-n|grep建立|wc–l90005现在终于可以得出一个比较正确的结论了。对于1个Ip的client,受ip\_local\_port\_range参数限制,也限制在65535。但是单个linux可以配置多个ip。如果有几个ip,最大理论值会翻几倍。不需要多个网卡。即使只有一张网卡,也可以配置多个IP。这就是k8s所做的。在k8s中,可以在一台物理机上部署多个pod。但是每个pod都会分配一个独立的ip,所以不用担心在物理机上部署过多的pod影响你使用的pod的TCP连接数。在给你ip的那一刻,你的pod就与其他应用程序隔离了。服务器端我们现在来回考虑服务器端。对于服务器,支持的最大并发连接数是多少?有人开始萌萌哒糊涂了:“服务端理论也是端口限制吗?”。好吧,假设我们的Nginx服务器仅在受到影响时监听端口80。那么Nginx只能接受一个TCP连接吗?这显然太荒唐了。好吧,让我们看看另一个更可靠的答案。也就是说,一个TCP连接是由一个四元组组成的。不管地址重用(unix的SO_REUSEADDR选项),对于我们的NginxServer来说,它的IP和端口是固定的。在cp连接四元组中,只有remoteip(即clientip)和remoteport(客户端端口)是可变的。它最多可以建立的连接数是2的32次方(ip数)×2的16次方(端口号)。这是一个很大的数,2.8*10的14次方,二兆万亿!!linux除了可以监听80,还可以监听其他端口,比如Mysql的3306,Redis的6339。当然你也可以把65535个端口都用上去监控。这样,理论上有2的32次方(ip数)×2的16次方(端口数)×2的16次方(服务器端口数)。有兴趣的可以算一下,这基本上就相当于无穷大了。但是,理想和现实总会有差距,因为Linux每维护一次TCP连接,都会消耗资源。处理连接请求、保持存活、收发数据都需要消耗一定的CPU,而维护TCP连接主要是消耗内存。我们题目的问题是考虑最大连接数,所以先不考虑数据的发送和接收。那么TCP在静态的时候,并不会消耗多少CPU,主要是消耗内存。在Linux上,内存是有限的。今天就直接抛出结论吧。如果一个TCP连接不发送数据,内存消耗约为3.3K。如果有数据要发送,需要为每个TCP分配一个发送缓冲区。大小受你参数net.ipv4.tcp_wmem配置的影响,默认最小为4K。如果发送结束,缓冲区消耗的内存将被回收。详细分析过程敬请期待下一篇文章。假设你只保持连接不发送数据,那么你的服务器最大可以建立的连接数=你的内存/3.3K。如果是4GB内存,那么可接受的TCP连接数在100万左右。在这个例子中,我们考虑的前提是将所有服务器端连接保持在一个进程下。在实际项目中,为了方便收发数据,很多网络IO模型也会为TCP连接创建一个线程或者协程。以最轻量级的golang为例,一个协程栈也需要2KB的内存开销。结论一台机器可以支持多少个网络连接?这道简单的问题其实埋下了一个坑,让无数大侠百思不得其解。就像树上九只鸟杀了一只还剩下多少只鸟的问题,我没告诉你这棵树是真鸟还是假鸟。也没有关于枪声是发声还是无声的消息。通过今天的分析,相信你终于可以骄傲的把这个问题摆在脚下了。TCP连接的客户端:理论上每个ip可以建立的TCP连接受ip\_local\_port\_range参数限制,也受限于65535。但是可以通过配置多个ip来增加建立连接的能力。**TCP连接的服务器机器:虽然每个监听端口的理论值很大,但是这个数字没有实际意义。最大并发数取决于你的内存大小,每个静态TCP连接需要消耗3.3K左右的内存。**我的公众号是《练内功》。在这里我不是简单地介绍技术理论,也不是只是介绍实践经验。而是理论联系实际,用实践加深对理论的理解,用理论提高技术实践能力。欢迎关注我的公众号,分享给你的朋友吧~~~