各位老铁们,大家好,今天由我来为大家分享8090s影视网站源码分享,以及的相关问题知识,希望对大家有所帮助。如果可以帮助到大家,还望关注收藏下本站,您的支持是我们最大的动力,谢谢大家了哈,下面我们开始吧!
我是一个Linux服务器上的进程,名叫小进。老是有人说我最多只能创建65535个TCP连接。我不信这个邪,今天我要亲自去实践一下。我走到操作系统老大的跟前,说:&34;老操不慌不忙,拿出一个表格递给我,&34;
我一看这个表,这不就是经典的socket四元组嘛。我只有一块网卡,其IP地址是123.126.45.68,我想要与110.242.68.3的80端口建立一个TCP连接,我将这些信息填写在了表中。
源端口号填什么呢?我记得端口号是16位的,可以有0~65535这个范围的数字,那我随便选一个吧!正当我犹豫到底选什么数字的时候,老操一把抢过我的表格。&34;&34;老操带着我的表格,走了。过了很长时间,老操终于回来了,并且带着一个纸条。
&34;我问道,&34;老操不耐烦地说道,&34;&34;我拿着这个文件描述符,把它放到属于我的内存中裱起来了,反正我只是想看看最多能创建多少TCP连接,又不是去真的用它,嘻嘻。
端口号
过了一分钟,我又去找老操了。&34;老操不慌不忙,拿出一个表格递给我,&34;
这回我熟悉了,只把目标IP和目标端口填好。
老操办好事之后,又带着一个纸条回来,上面写着数字&34;。就这样,我每隔一分钟都去找老操建立一个新的TCP连接,目标IP都是110.242.68.3,目标端口都是80。老操也很奇怪,不知道我在这折腾啥,他虽然权力大,但无权拒绝我的指令,每次都兢兢业业地把事情办好,并给我一张一张写着文件描述符的纸条。直到有一次,我收到的纸条有些不同。
我带着些许责怪的语气问,&34;老操也没好气地说,&34;我也不是那么好骗的,质疑道。&34;老操鄙视地看了我一眼,&34;
[root]34;看到没,当前的限制是1024~65000,所以你就只能有63977个端口号可以使用。&34;哎哟真是抱歉,还是我见识太少,那这个数可以修改么?&34;可以的,具体可以vim/etc/sysctl.conf这个文件进行修改,我们在这个文件里添加一行记录&34;保存好后执行sysctl-p/etc/sysctl.conf使其生效。这样你就只有10个端口号可以用了,就会更快报出端口号不够用的错误&34;原来如此,谢谢老操又给我上了一课。&34;这又是咋回事?&34;呵呵,你小子以为突破端口号限制就无法无天了?现在文件描述符不够用啦!&34;怎么啥啥都有限制啊?你们操作系统给我们的限制也太多了吧?&34;废话,你看看你都建了多少个TCP连接了!每建立一个TCP连接,我就得分配给你一个文件描述符,linux对可打开的文件描述符的数量分别作了三个方面的限制。&cat/proc/sys/fs/file-max
100000
[root~]cat/etc/security/limits.conf
…
*softnproc100000
*hardnproc100000
原来如此,我记得刚刚收到的最后一张纸条是。
再之后就收到文件描述符不够的错误了。我又请教老操,&34;老操仍然耐心地告诉我,&34;
echo100>/proc/sys/fs/nr_open
&34;&34;老操再次用鄙视的眼睛看着我。
线程
突破了文件描述符限制,我又开始肆无忌惮地创建起了TCP连接。但我发现,老操的办事效率越来越慢,建立一个TCP连接花的时间越来越久。有一次,我忍不住责问老操,&34;老操也忍不住了,&34;
听完老操的抱怨,我想起了之前似乎有人跟我说过C10K问题,就是当服务器连接数达到1万且每个连接都需要消耗一个线程资源时,操作系统就会不停地忙于线程的上下文切换,最终导致系统崩溃,这可不是闹着玩的。我赶紧像操作系统老大请教,&34;老操无奈地说,&34;你现在这种每建一个TCP连接就创建一个线程的方式,是最传统的多线程并发模型,早期的操作系统也只支持这种方式。但现在我进化了,我还支持IO多路复用的方式,简单说就是一个线程可以管理多个TCP连接的资源,这样你就可以用少量的线程来管理大量的TCP连接了。
我一脸疑惑,&34;。老操一脸鄙视,&34;这次真是大开眼界了,我赶紧把代码改成了这种IO多路复用的模型,将原来的TCP连接销毁掉,改成同一个线程管理多个TCP连接,很快,操作系统老大就恢复了以往的办事效率,同时我的TCP连接数又多了起来。
内存
突破了端口号、文件描述符、线程数等重重限制的我,再次肆无忌惮地创建起了TCP连接。直到有一次,我又收到了一张红牌。
嗨,又是啥东西限制了呀,改了不就完了。我不耐烦地问老操,&34;老操说道。&34;
我看这次老操特别耐心,也没多说什么,但想着被内存限制住了,有点不太开心,于是我让老操帮我最后一个忙。&34;老操见我真的是够拼的,便答应了我,杀死了好多进程,我很是感动。
CPU
有了老操为我争取的内存资源,我又开始日以继日地创建TCP连接。老操也不再说什么,同样日以继日地执行着我的指令。有一次,老操语重心长地对我说,&34;
我觉得老操这人真的可笑,经过这几次的小挫折,我明白了只要思想不滑坡,方法总比苦难多,老操这人就是太谨慎了,我岂能半途而废,不管他。我仍然继续创建着TCP连接。直到有一天,老操把我请到一个小饭馆,一块吃了顿饭,吃好后说道。&34;我很不解地问,&34;老操
说,&34;我大惊失色,&34;老操缓缓起身,&34;突然,我眼前一黑,一切都没了。
总结
资源
一台Linux服务器的资源
一个TCP连接占用的资源
占满了会发生什么
CPU
看你花多少钱买的
看你用它干嘛
电脑卡死
内存
看你花多少钱买的
取决于缓冲区大小
OOM
临时端口号
ip_local_port_range
1
cannotassignrequestedaddress
文件描述符
fs.file-max
1
toomanyopenfiles
进程\\线程数
ulimit-n
看IO模型
系统崩溃
——————————————追更———————————————-
想不到突然获得这么多赞,其实我写的原文中还有后记部分,被我删了,因为有几个动图总是动不起来,大家感兴趣的话可以再看看原文哈。
最多能创建多少个TCP连接?
编辑于2021-05-0714:15
赞同3933??88条评论
?分享
?收藏?喜欢
?
收起?
更多回答
张彦飞
?
?
北京搜狗网络技术有限公司专家开发工程师
?关注
2,240人赞同了该回答
几年前的我也产生过同样的困惑。
为了给自己解惑,我扒内核源码,做测试实验,写技术文章,从头到尾把这个问题扒了一遍。
要想把这个问题搞清楚,关键的地方在于要把TCP连接的两端里的客户端和服务端两个角色分开来讨论。因为它两对端口号的使用方式不一样,区分开了能讨论的更清晰。
先抛出结论,无论是服务端还是客户端,单机支撑100W以上的连接都是没有问题的。
我在4GB的机器上都测试过的。如果内存更大,能支持的连接数会更多。咱们先从理论讲起来。
一、TCP并发理论基础
1服务器理论最大并发数
TCP连接四元组是由源IP地址、源端口、目的IP地址和目的端口构成。
当四元组中任意一个元素发生了改变,那么就代表的是一条完全不同的新连接。
我们算下服务器上理论上能达成的最高并发数量。拿我们常用的Nginx举例,假设它的IP是A,端口80。这样就只剩下源IP地址、源端口是可变的。
IP地址是一个32位的整数,所以源IP最大有2的32次方这么多个。端口是一个16位的整数,所以端口的数量就是2的16次方。
2的32次方(ip数)×2的16次方(port数)大约等于两百多万亿。
所以理论上,我们每个server可以接收的连接上限就是两百多万亿。(不过每条TCP连接都会消耗服务器内存,实践中绝不可能达到这个理论数字,稍后我们就能看到。)
2客户端理论最大并发数
注意:这里的客户端是一个角色,并不具体指的是哪台机器。当你的java/c/go程序响应用户请求的时候,它是服务端。当它访问redis/mysql的时候,你这台机器就变成客户端角色了。这里假设我们一台机器只用来当客户端角色。
我们再算一下客户端的最大并发数的上限。
很多同学认为一台Linux客户端最多只能发起64k条TCP连接。因为TCP协议规定的端口数量有65535个,但是一般的系统里1024以下的端口都是保留的,所以没法用。可用的大约就是64k个。
但实际上客户端可以发出的连接远远不止这个数。咱们看看以下两种情况
情况1:这个64k的端口号实际上说的是一个ip下的可用端口号数量。而一台Linux机器上是可以配置多个IP的。假如配置了20个IP,那这样一台客户端机就可以发起120万多个TCP连接了。
情况2:再退一步讲,假定一台Linux上确实只有一个IP,那它就只能发起64k条连接了吗?其实也不是的。
根据四元组的理论,只要服务器的IP或者端口不一样,即使客户端的IP和端口是一样的。这个四元组也是属于一条完全不同的新连接。
比如下面的两条连接里,虽然客户端的IP和端口完全一样,但由于服务器侧的端口不同,所以仍然是两条不同的连接。
连接1:客户端IP10000服务器IP10000连接2:客户端IP10000服务器IP20000
所以一台客户端机器理论并发最大数是一个比服务器的两百万亿更大的一个天文数字(因为四元组里每一个元素都能变)。这里就不展开计算了,因为已经没有意义了。
3Linux最大文件描述符限制
linux下一切皆文件,包括socket。所以每当进程打开一个socket时候,内核实际上都会创建包括file在内的几个内核对象。该进程如果打开了两个socket,那么它的内核对象结构如下图。
进程打开文件时消耗内核对象,换一句直白的话就是打开文件对象吃内存。所以linux系统出于安全角度的考虑,在多个位置都限制了可打开的文件描述符的数量,包括系统级、进程级、用户进程级。
fs.file-max:当前系统可打开的最大数量fs.nr_open:当前系统单个进程可打开的最大数量nofile:每个用户的进程可打开的最大数量
本文的实验要涉及对以上参数的修改。
4TCP连接的内存开销
介绍内存开销之前,需要先理解内核的内存使用方式。只有理解了这个,才能深刻理解TCP连接的内存开销。
Linux内核和应用程序使用的是完全不同的两套机制。Linux给它的内核对象分配使用SLAB的方式。
一个slab一般由一个或者多个Page组成(每个Page一般为4KB)。在一个slab内只分配特定大小、甚至是特定的对象。这样当一个对象释放内存后,另一个同类对象可以直接使用这块内存。通过这种办法极大地降低了碎片发生的几率。
Linux提供了slabtop命令来按照占用内存从大往小进行排列,这对我们查看内核对象的内存开销非常方便。
在Linux3.10.0版本中,创建一个socket需要消耗densty、flip、sock_inode_cache、TCP四个内核对象。这些对象加起来总共需要消耗大约3KB多一点的内存。
如果连接上有数据收发的话,还需要消耗发送、接收缓存区。这两个缓存区占用内存影响因素比较多,既受收发数据的大小,也受tcp_rmem、tcp_wmem等内核参数,还取决于服务器进程能否及时接收(及时接收的话缓存区就能回收)。总之影响因素比较多,不同业务之间实际情况差别太大,比较复杂。所以不在本文讨论范围之内。
二、百万连接达成实验
了解了理论基础后,其实你的疑惑就得到基本的解释了。剩下的事情你可以把我的这本电子书下载回去慢慢看。
下载地址在这里:
飞哥的《理解了实现再谈网络性能》电子书发布啦!?mp.weixin.qq.com/s/xlRxat5F-G6eZqY9M2JDog
咱们来接着继续来看实验过程。
本实验需要准备两台机器。一台作为客户端,另一台作为服务器。如果你选用的是c或者php源码,这两台机器内存只要大于4GB就可以。如果使用的是Java源码,内存要大于6GB。对cpu配置无要求,哪怕只有1个核都够用。
本方案中采用的方法是在一台客户端机器上配置多个ip的方式来发起所有的tcp连接请求。所以需要为你的客户端准备20个IP,而且要确保这些IP在内网环境中没有被其它机器使用。如果实在选不出这些IP,那么可以采用百看不如一练,动手测试单机百万连接的保姆级教程!一文中的方案二。
除了用20个IP以外,也可以使用20台客户端。每个客户端发起5万个连接同时来连接这一个server。但是这个方法实际操作起来太困难了。
客户端机和服务器分别下载源码:
https://github.com/yanfeizhang/coder-kung-fu/tree/main/tests/network/test02
下面我们来详细看每一个实验步骤。
1调整客户端可用端口范围
默认情况下,Linux只开启了3万多个可用端口。但我们今天的实验里,客户端一个进程要达到5万的并发。所以,端口范围的内核参数需要修改。
vi/etc/sysctl.conf
fs.file-max=1100000
fs.nr_open=60000
sysctl-p使得设置生效。并使用sysctl-a查看是否真正work。
sysctl-a
fs.file-max=1100000
fs.nr_open=60000
接着再加大用户进程的最大可打开文件数量限制(nofile)。这两个是用户进程级的,可以按不同的用户来区分配置。这里为了简单,就直接配置成所有用户*了。每个进程最大开到5万个文件数就够了。同样预留一点余地,所以设置成55000。这些是在/etc/security/limits.conf文件中修改。
注意hardnofile一定要比fs.nr_open要小,否则可能导致用户无法登陆。
ulimit-n
55000
3服务器最大可打开文件句柄调整
服务器系统级参数fs.file-max也直接设置成110万。另外由于这个方案中服务器是用单进程来接收客户端所有的连接的,所以进程级参数fs.nr_open,也一起改成110万。
vi/etc/security/limits.conf
*softnofile1010000
*hardnofile1010000
配置完后,开个新控制台即可生效。使用ulimit命令校验是否成功生效。
4为客户端配置额外20个IP
假设可用的ip分别是CIP1,CIP2,……,CIP20,你也知道你的子网掩码。
注意:这20个ip必须不能和局域网的其它机器冲突,否则会影响这些机器的正常网络包的收发。
在客户端机器上下载的源码目录test02中,找到你喜欢用的语言,进入到目录中找到tool.sh。修改该shell文件,把IPS和NETMASK都改成你真正要用的。
为了确保局域网内没有这些ip,最好先执行代码中提供的一个小工具来验证一下
makeping
当所有的ip的ping结果均为false时,进行下一步真正配置ip并启动网卡。
makeifup
使用ifconfig命令查看ip是否配置成功。
34;ss-ant|grepESTABLISH&defineINET_MATCH(__sk,__net,__cookie,__saddr,__daddr,__ports,__dif)\\
((inet_sk(__sk)->inet_portpair==(__ports))&&\\
(inet_sk(__sk)->inet_daddr==(__saddr))&&\\
(inet_sk(__sk)->inet_rcv_saddr==(__daddr))&&\\
(!(__sk)->sk_bound_dev_if||\\
((__sk)->sk_bound_dev_if==(__dif)))&&\\
net_eq(sock_net(__sk),(__net)))
保证客户端使用了相同端口的两条连接不串线的原因就在INET_MATCH这里。在这个函数里不仅仅是比较了客户端的端口号,包括四元组在内的标识都比较了一遍。(注意下,每个socket上都保存了连接四元组等信息,所以才能比较)
所以:对于下面这两条连接,因为服务器端口不同,所以当服务器发送数据过来的时候INET_MATCH可以精确定位到连接,而不会串线。
连接1:客户端IP110000服务器IP8090连接2:客户端IP110000服务器IP8091
而且除了内核源码之外,我也还进行了实际测试,而且文中我还提供出来了测试源码,你想玩也可以玩玩。参见:
百看不如一练,动手测试单机百万连接的保姆级教程!漫画|理解了TCP连接的实现以后,客户端的并发也爆发了!
我再给大伙儿贴一下我实验时候在客户机上实验时的实际截图,来实际看一下一个端口号确实是被用在了多条连接上了。
截图中左边的192是客户端,右边的119是服务器的ip。可以看到客户端的10000这个端口号是用在了多条连接上了的。
如果你在客户端非得使用bind还想让端口重用,那可以开启so_reuseport试试,不过我觉得有点多此一举。
最后,我再来说一下我的个人电子书《理解了实现再谈网络性能》的创作思路。
我觉得业界里计算机网络的知识太多都聚集于协议层面了,太过于偏向理论。而对于网络在机器是如何被实现的,开销如何,这部分知识在业界里太少了。比如网络是如何使用cpu的,如何使用内存的,这些只是感觉在整个业界说很匮乏也不为过。
我的整本电子书是对网络性能进行拆解,把性能拆分为三个角度:CPU开销、内存开销等。
具体到某个角度比如CPU,那我需要给自己解释清楚网络包是怎么从网卡到内核中的,内核又是通过哪些方式通知进程的。只有理解清楚了这些才能真正把握网络对CPU的消耗。
对于内存角度也是一样,只有理解了内核是如何使用内存,甚至需要哪些内核对象都搞清楚,也才能真正理解一条TCP连接的内存开销。
除此之外我还增加了一些性能优化建议和前沿技术展望等,最终汇聚出了这本《理解了实现再谈网络性能》。在此无私分享给大家。
下载链接传送门:《理解了实现再谈网络性能》
Github:https://github.com/yanfeizhang/coder-kung-fu
编辑于2021-04-2309:53
真诚赞赏,手留余香
赞赏
还没有人赞赏,快来当第一个赞赏的人吧!
?赞同2240??98条评论
?分享
?收藏?喜欢
?
收起?
文礼
?
?
游戏开发等2个话题下的优秀答主
?关注
417人赞同了该回答
正确的说法是,服务端的一个特定的TCP端口,只能最多和一个特定的客户端同时保持最多64k个链接。并且,这还只是服务端和客户端各自只有一个IP地址的情况。
就如别的回答提到的,TCP连接依靠服务端IP、服务端端口号、客户端IP、客户端端口号这4个元素来标识。当服务端IP、客户端IP固定时,因为端口号是16bit整数,所以任何一个服务端端口可以和64k个客户端端口形成连接,反之亦然。也就是特定的客户端和特定的服务端之间总共可能的同时TCP连接为64kx64k=4G个。
但是当客户端IP不同时,它们可以用同一个客户端端口连接到同一个服务端端口。上面的4个因素当中,只要有一个不同,就是不同的连接。
所以理论上,一个服务端端口可以服务最多大约2^32(IPv4)x64k个客户端连接。当然,有一些IP地址为特殊地址,比如广播地址、组播地址、以及诸如10.x.x.x/192.168.x.x这样的本地地址等,对于互联网服务需要排除。
此外,由于操作系统需要为每个连接分配内存以及文件描述子,所以实际能支持的数量远小于理论值。linux系统的通常缺省设置,同时支持的文件描述子在30万上下,内存则每连接独享的至少在1k上下,那么30万连接就在300MB附近。虽然300MB对于当今的服务器物理内存容量可能不是一个很大的数值,但是注意这是操作系统内核空间的内存,非用户态空间。当然,这些限制都是可以通过配置内核参数进行修改的,至少linux是肯定可以的。
实战当中,一般单台服务器的同时TCP连接上限按8万上下估计。这不是一个确切的理论值,只是经验值。而且这只是仅仅考虑TCP连接,不考虑后面的实际工作负载。
文章分享结束,8090s影视网站源码分享和的答案你都知道了吗?欢迎再次光临本站哦!
