你接触过的单机最大并发数是多少?
操作系统最大文件打开数是65535,服务器又是怎么做到支持10w并发的?
你认为当前正常配置的服务器物理机最大并发数可以到多少?
说说你的理解与分析
作为一个运维人员拿到一台服务器,需要完成哪些基线配置、内核优化参数你一定可以有理有据至少说出一二,但若要问题原理为何、凭什么并发与最大文件打开数有关又不完全有关,这是这篇文章给大家分享的。
四元组({localip, localport,remoteip,remoteport}): 在TCP连接中,最常用的标识方式是四元组,包括源IP地址、源端口号、目标IP地址和目标端口号。这四个值唯一地标识了一个TCP连接。这被称为源IP地址、源端口号、目标IP地址和目标端口号的组合。
Socket句柄(五元组): 在编程中,TCP连接通常通过套接字(Socket)来表示和标识。一个Socket句柄通常由以下组成:协议(如TCP)、本地IP地址、本地端口号、远程IP地址和远程端口号。这些信息用于在编程中标识和操作TCP连接。
连接标识符: 在某些情况下,应用程序可能使用连接标识符或会话ID来唯一标识连接。这个标识符可以是应用程序自己定义的,用于跟踪和管理连接。
TCP状态: 除了上述的标识方式,TCP连接还可以通过其当前状态来标识。TCP协议定义了多种状态,如建立连接、数据传输、连接关闭等。连接的状态可以用来识别连接的当前阶段。
明确了四元组来标识一个tcp连接,那么这样的tcp连接理论最大值应该取决于 源地址、源端口、目的地址、目的端口等四个维度的最大值来定义。
如图,理论最大并发数=服务器唯一五元组,端口、地址、协议都是有上限的,这个值不难算出。
client每次发起tcp连接请求时,除非指定源端口,通常会随机选出来一个空闲的本地端口(基本上你看到都是五位数以上),该端口是独占不存在复用。因此操作系统端口数最多65536,0 又不能用,最多就剩下65535个,因此在纯客户端的情况下,不管连一样的服务器地址和端口或者不一样的服务器端口他最大值始终都受限制与客户端本地的端口数量,然后一般1024以下又不让你用 所以客户端的最大连接数最多不会超过65000,理论就是2^16个.
关于这个客户端的最大连接数还有一个场景是NAT客户端的场景,同一个NAT网络下,所有终端都是通过路由NAT了一个公网地址+端口进行访问,这种情况下,所有终端的最大连接数合计应该是<65535的。
那么对于服务器端来说,我们以TCP连接为例,我们假定单进程、单端口(注意这个前提,要考),单网卡。 这个条件下 四元组中两项固定,那么服务器端的最大连接数理论值应该就是客户端的IP地址数量客户端的端口数量即2^32*2^16=2^48个。
但是,但是来了
每一条连接都是要消耗系统资源的,一个socket连接的建立需要消耗内存、需要建立socket,每个socket又都需要消耗一个文件描述符,文件描述符消耗的就是文件打开数,因此,如果你的最大文件打开数是1024,那么你的socket最多也就1024。
另外,一个socket是可以建立多个连接的,一个tcp连接标记为一个四元组,只要四个元素有一个不一样那么就不是一个连接。
比如:
服务器ip是214.117.11.2,监听80端口;
115.116.117.118 发来一条请求源端口为11111,这条tcp连接的四元组是(214.117.11.2,80,115.116.117.118,11111)
115.116.117.118 发来第二条请求,端口11112,新的四元组(214.117.11.2,80,115.116.117.118,11112).那么你的80端口就有了两条连接;
若115.116.117.118 发来第三条请求,源端口还是11111,这个链接肯定无法建立,因为源端口不可复用,当然你换udp 是不是就可以了,因为udp 跟tcp 属于不同协议,并不共享端口,协议不同,端口相同在操作系统中是允许存在。所以真正要标识一个链接是五元组,比四元组多了一个协议。
综上所述,现实工作中,由于存在端口复用的情况,服务器同时支持tcp连接数跟端口的65535 没有一一对应关系,而进程又跟文件描述符是一一对应关系,文件描述符消耗最大文件打开数,同时需要内存来维护。因此最大并发数受最大文件打开数、内存影响。
/proc/sys/fs/file-max中指定了系统范围内所有金策会给你可打开的文件句柄的数量限制(系统级别、kernel-level)
The value in file-max denotes the maximum number of file handles that the linux kernel will allocate
临时性设置:
echo 6553500 > /proc/sys/fs/file-max
永久:
fs.file-max=6553500
nr_open 单个进程可分配的最大文件数
为什么会提到这个参数,毕竟很少有人真的去改一个最大文件打开数超过1024*1024=1048576.更别说有人会去测试,比如最大文件打开数超过这个值,测试(慎用,建议测试环境使用,在你不知道这个脚本是什么功能的前提下,不要复制直接运行):
for i in `seq 100000 10000000`;do ulimit -n $i; [[ $? != 0 ]] && break;done
跟踪原因就会发现,这个实际的ulimit值还受nr_open的限制。
这里贴下官网linux内核的解释:
file-max:
The value in file-max denotes the maximum number of file-handles that the linux kernel will allocate. When you get lots of error messages about running out of file handles, you might want to increase this limit
nr_open
This denotes the maximum number of file-handles a process can allocate. Default value is 1024*1024 which should be enough for most machines. Actual limit depends on RLIMIT_NOFILE resource limit.
根据解释,其实file-max是文件句柄,而非FD(文件描述符)。因此 file-max是内核可分配的最大文件数,nr_open是单个进程可分配的最大文件数。
临时修改:
ulimit -n 65535
永久(要重启服务器):
# /etc/security/limits.conf
* soft nofile 65535
* hard nofile 65535
这里可能有运维同学会遇到这种问题:改了ulimit改了nofile 改了fs.file-max,但是使用yum安装的服务,却一直报文件打开数不足,服务器重启就是不生效。原因是通过sytemd管理的服务,需要在这里也要修改最大文件打开数。当然比如MySQL 自身的mysqld.service中也可以来配置这个参数实现修改。
(为什么出现这样的原因呢,主要看systemd服务本身是什么状态,是系统实例还是用户实例,通常都是系统实例,把--system换位--user 即可。)回到上面的问题,mysql是通过systemd管理的所以需要修改system.conf中的最大文件打开数,重启服务即可。如果还有限制检查
/usr/lib/systemd/system/mysqld.service
结论:
所有进程打开的文件描述符数量不能超过/proc/sys/fs/file-max
单个进程打开的文件描述符数不能超过user limit 中nofile soft limit
nofile 的soft limit 不能超过hard limit
nofile 的hard limit 不能超过 /proc/sys/fs/nr_open