一台机器最多能撑多少个TCP链接? 今天掰扯清楚!

在网络开发中,我发现有不少同窗对一个基础问题始终是没有完全搞明白。那就是一台机器最大究竟能支持多少个网络链接?我想我有必要单独发一篇文章来好好说一下这个问题。不少同窗看到这个问题的第一反应是65535。缘由是:“据说端口号最多有65535个,那长链接就最多保持65535个了”。是这样的吗?还有的人说是应该受TCP链接里四元组的空间大小限制,这样算起来就是很是很是大的一个数字了。这两个答案都对,也都不对。php

其实要想把这个问题搞清楚,最最最关键的地方在于要把TCP链接的两端里的角色分清楚-客户端和服务器端。你手头的任何一台服务器,通常状况下都便是服务器,又是客户端。例如对于你的开发的后端接口,对于用户来讲你是服务器端。但你得请求Redis、Mysql去获取数据,这时候又变成了客户端。若是不把这台机器做为客户端和服务器端两种角色拆开来理解,你将永远被这个问题困惑下去。 因此本文分别从客户端、服务端两块来展开聊聊。golang

客户端

如今咱们单独来讲客户端,当一台机器做为客户端的时候,究竟能支持多少个TCP链接? 空嘴说没有啥意思,咱们直接用代码来试试。sql

1.小试牛刀

开始实验以前咱们先来check下手头机器上的端口数量的配置后端

$ sysctl -a | grep ip_local_port_range
net.ipv4.ip_local_port_range = 15000	65000

经过上述内核参数的输出看到内核开放了50000个端口能够供TCP链接使用。接下来是一段看起来长,但其实很是简单的TCP客户端链接的代码。用它来链接你的任意一个TCP Server,好比Nginx、Redis啥的均可以。缓存

file

我经过这段代码对个人某台机器上的Nginx发起了链接服务器

$ php client1.php 某台服务器IP 80

经过netstat命令看到链接数量稳步上升,但当上升到5W的时候,出现了一条报错网络

socket_connect() 失败的缘由是:Cannot assign requested address

回头想一想咱们的ip_local_port_range参数值,65000-15000就只开放了5万个。实际上是超过这个限制了。 这个时候咱们彷佛能够初步得出一个相结论.当Linux做为客户端创建链接的时候,最大链接数量是受内核参数net.ipv4.ip_local_port_range限制 而ip_local_port_range是可配置的,最大理论范围是0-65535并发

进阶

若是这个时候你相信了我上面的结论的话,就又被我带了沟里了。为何这么说,让咱们来看下面的实验。socket

首先经过ifconfig命令看到个人机器上有两块网卡,每块网卡都已经配置好了一个ip。tcp

file

接着咱们修改一下第一个实验的代码,在发起链接以前容许使用socket_bind来绑定ip。

file

接下来咱们分别启动两个控制台,分别执行一下代码。其中10.143.x.x和10.153.x.x是实验用机的两个网卡ip。

$ php client1.php 10.143.x.x 某台服务器IP 80
$ php client2.php 10.153.x.x 某台服务器IP 80

这个时候经过ss命令监控本机的ESTABLISH链接,发现已经突破5万,并向10万逼近了。

$ ss -n | grep ESTAB | wc –l
90005

如今咱们终于能够得出更为正确的结论了,对于有1个Ip的客户端来讲,受限于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选项)的状况下,对于咱们这台Nginx Server来讲,它的IP和端口是固定的。cp链接4元组中只有remote ip(也就是client ip)和remote port(客户端port)是可变的。它可能创建的最大的链接数是2的32次方(ip数)×2的16次方(port数)。这是2.8*10的14次方的一个大数字,两百万亿!!

Linux上除了监听80之外,还能够监听其它的端口,例如Mysql的3306, Redis的6339,固然全部65535个端口你均可以用来监听一遍。这样理论上线就到了2的32次方(ip数)×2的16次方(port数)×2的16次方(服务器port数)个。感兴趣你能够算一下,这个基本至关于无穷个了。

不过理想和实际老是会有差距的,由于Linux每维护一条TCP链接都要花费资源。处理链接请求,保活,数据的收发时须要消耗一些CPU,维持TCP链接主要消耗内存。咱们题目的问题是考虑最大多少个链接,因此咱们先不考虑数据的收发。那么TCP在静止的状态下,就不怎么消耗CPU了,主要消耗内存。而Linux上内存是有限的。
咱们今天先直接把结论抛出来,一条TCP链接若是不发送数据的话,消耗内存是3.3K左右。若是有数据发送,须要为每条TCP分配发送缓存区,大小受你的参数net.ipv4.tcp_wmem配置影响,默认状况下最小是4K。若是发送结束,缓存区消耗的内存会被回收详细的分析过程敬请期待接下来的另外一篇文章。

假设你只保持链接不发送数据,那么你服务器能够创建的链接最大数量 = 你的内存/3.3K。 假如是4GB的内存,那么大约可接受的TCP链接数量是100万左右。

这个例子里,咱们考虑的前提是在一个进程下hold全部的服务器端链接。而在实际中的项目里,为了收发数据方便,不少网络IO模型还会为TCP链接再建立一个线程或协程。拿最轻量的golang来讲,一个协程栈也须要2KB的内存开销。

结论

一台机器最大究竟能支持多少个网络链接?这个简单的问题里其实埋了坑,致使无数的英雄好汉被困惑不解。就和树上九只鸟打死一只还剩几只的问题同样,没有和你说清楚树上是真鸟,仍是假鸟。也没有说枪是有声仍是无声的。经过今天的分析,相信你终于能够扬眉吐气把这个问题踩在脚下摩擦了。

  • TCP链接的客户端机:每个ip可创建的TCP链接理论受限于ip_local_port_range参数,也受限于65535。但能够经过配置多ip的方式来加大本身的创建链接的能力。
  • TCP链接的服务器机:每个监听的端口虽然理论值很大,但这个数字没有实际意义。最大并发数取决你的内存大小,每一条静止状态的TCP链接大约须要吃3
    .3K的内存。

个人公众号是「开发内功修炼」,在这里我不是单纯介绍技术理论,也不仅介绍实践经验。而是把理论与实践结合起来,用实践加深对理论的理解、用理论提升你的技术实践能力。欢迎你来关注个人公众号,也请分享给你的好友~~~

相关文章
相关标签/搜索