前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

一、一台服务器最大能打开的文件数

1、限制参数

我们知道在 Linux 中一切皆文件,那么一台服务器最大能打开多少个文件呢?Linux 上能打开的最大文件数量受三个参数影响,分别是:

参数 级别 说明
fs.file-max 系统 该参数描述了整个系统可以打开的最大文件数量。但是 root 用户不会受该参数限制(比如:现在整个系统打开的文件描述符数量已达到 fs.file-max ,此时 root 用户仍然可以使用 pskill 等命令或打开其他文件描述符)
soft nofile 进程 限制单个进程上可以打开的最大文件数。只能在 Linux 上配置一次,不能针对不同用户配置不同的值
fs.nr_open 进程 限制单个进程上可以打开的最大文件数。可以针对不同用户配置不同的值

这三个参数之间还有耦合关系,所以配置值的时候还需要注意以下三点:

1、如果想加大 soft nofile ,那么 hard nofile 参数值也需要一起调整。如果因为 hard nofile参数值设置的低,那么soft nofile 参数的值设置的再高也没有用,实际生效的值会按照二者最低的来。

2、如果增大了 hard nofile,那么 fs.nr_open 也都需要跟着一起调整( fs.nr_open 参数值一定要大于 hard nofile参数值)。如果不小心把 hard nofile 的值设置的比 fs.nr_open 还大,那么后果比较严重。会导致该用户无法登录,如果设置的是*,那么所有用户都无法登录

3、如果加大了 fs.nr_open,但是是用的 echo "xxx" > ../fs/nr_open 命令来修改的 fs.nr_open 的值,那么刚改完可能不会有问题,但是只要机器一重启,那么之前通过echo命令设置的fs.nr_open值便会失效,用户还是无法登录。所以非常不建议使用echo的方式修改内核参数!!!

2、调整服务器能打开的最大文件

假设想让进程可以打开 100 万个文件描述符,这里用修改 conf 文件的方式给出一个建议。如果日后工作里有类似的需求可以作为参考。

vim /etc/sysctl.conf
fs.file-max=1100000 // 系统级别设置成110万,多留点buffer
fs.nr_open=1100000 // 进程级别也设置成110万,因为要保证比 hard nofile大

使上面的配置生效 sysctl -p

vim /etc/security/limits.conf
// 用户进程级别都设置成100完
soft nofile 1000000
hard nofile 1000000

二、一台服务器最大能支持多少连接

我们知道 TCP连接,从根本上看其实就是 clientserver 端在内存中维护的一组【socket 内核对象】(这里也对应着 TCP四元组:源 IP、源端口、目标 IP、目标端口),他们只要能够找到对方,那么就算是一条连接。那么一台服务器最大能建立多少条连接呢?

问题1:理论上能支持多少连接呢?

答案:理论值:由于 TCP 连接本质上可以理解为是 client - server 端的一对 socket 内核对象,那么从理论上将应该是【2^32 (ip数) * 2^16 (端口数)】条连接(约等于两百多万亿)

问题2:实际上能达到那么多的连接吗?

答案:实际值:但是实际上由于受其他软硬件的影响,我们一台服务器不可能能建立这么多连接(主要是受 CPU 和 内存限制)

问题3:那如果不传入数据,只建立连接能支持多少呢?

答案:如果只以 ESTABLISH 状态的连接来算(这些连接只是建立,但是不收发数据也不处理相关的业务逻辑)那么一台服务器最大能建立多少连接呢?以一台 4GB内存的服务器为例!

这种情况下,那么能建立的连接数量主要取决于【内存的大小】(因为如果是)ESTABLISH 状态的空闲连接,不会消耗 CPU(虽然有TCP 保活包传输,但这个影响非常小,可以忽略不计)

我们知道一条 ESTABLISH 状态的连接大约消耗【3.3KB内存】,那么通过计算得知一台 4GB 内存的服务器,【可以建立 100w+TCP 连接】(当然这里只是计算所有的连接都只建立连接但不发送和处理数据的情况,如果真实场景中有数据往来和处理(数据接收和发送都需要申请内存,数据处理便需要 CPU ),那便会消耗更高的内存以及占用更多的 CPU,并发不可能达到 100w+

问题4:那建立连接后,又能支持多少呢?

答案:上面讨论的都是进建立连接的理想情况,在现实中如果有频繁的数据收发和处理(比如:压缩、加密等),那么一台服务器能支撑1000 连接都算好的了,所以一台服务器能支撑多少连接还要结合具体的场景去分析,不能光靠理论值去算。抛开业务逻辑单纯的谈并发没有太大的实际意义。

最重要的是:服务器的开销大头往往并不是连接本身,而是每条连接上的数据收发,以及请求业务逻辑处理!!

三、一台客户端机器最多能发起多少条连接

问题1:理论上能支持多少连接呢?

答案:我们知道客户端每和服务端建立一个连接便会消耗掉 client 端一个端口。一台机器的端口范围是【0 ~ 65535】,那么是不是说一台 client 机器最多和一台服务端机器建立 65535 个连接呢(这 65535个端口里还有很多保留端口,可用端口可能只有 64000个左右)?

TCP 连接的四元组特性可知,只要四元组里某一个元素不同,那么就认为这是不同的 TCP 连接。所以需要分情况讨论

【情况一】:如果一台 client 仅有一个 IPserver 端也仅有一个 IP 并且仅启动一个程序,监听一个端口的情况下,client 端和这台 server 端最大可建立的连接条数就是 65535 个。

原因:因为源IP固定,目标 IP 和端口固定,四元组中唯一可变化的就是【源端口】,【源端口】的可用范围又是【0 ~ 65535】,所以一台 client 机器最大能建立 65535个连接

以现在的技术,给一个 client 分配多个 IP 是非常容易的事情,只需要去联系你们网管就可以做到。

【情况二】:如果一台 client有多个IP(假设客户端有 nIP),server 端仅有一个IP并且仅启动一个程序,监听一个端口的情况下,一台 client 机器最大能建立的连接条数是:n· * 65535

原因:因为目标 IP 和端口固定,有 n 个源 IP,四元组中可变化的就是【源端口】+ 【源IP】,【源端口】的可用范围又是【0 ~ 65535】,所以一个IP最大能建立 65535个连接,那么 nIP 最大就能建立 n *65535个连接了

【情况三】:如果一台 client 仅有一个 IPserver 端也仅有一个 IP 但是 server 端启动多个程序,每个程序监听一个端口的情况下(比如server 端启动了m个程序,监听了 m 个不同端口),一台 client 机器最大能建立的连接数量为:65535 * m`

原因:源 IP 固定,目标 IP 固定,目标端口数量为 m个,可变化的是源端口,而源端口变化范围是【0 ~ 65535】,所以一台 client机器最大能建立的TCP连接数量是 6553 * m

其余情况类推,但是客户端的可用端口范围一般达不到 65535个,受内核参数 net.ipv4.ip_local_port_range 限制,如果要修改client 所能使用的端口范围,可以修改这个内核参数的值。

所以,不光是一台 server 端可以接收 100w+TCP 连接,一台 client照样能发出 100w+个连接

四、其他问题

1、”too many open files” 报错是怎么回事,该如何解决

你在线上可能遇到过 too many open files 这个错误,那么你理解这个报错发生的原理吗?如果让你修复这个错误,应该如何处理呢? 需要注意这三个参数之间的耦合关系!

1、因为每打开一个文件(包括 socket),都需要消耗一定的内存资源。为了避免个别进程不受控制的打开了过多文件而让整个服务器奔溃,Linux 对打开的文件描述符数量有限制。如果你的进程触发到内核的限制,那么” too many open files” 报错就产生了

2、可以通过修改 fs.file-maxsoft nofilefs.nr_open 这三个参数的值来修改进程能打开的最大文件描述符数量

2、一台服务端机器最大究竟能支持多少条连接

因为这里要考虑的是最大数,因此先不考虑连接上的数据收发和处理,仅考虑 ESTABLISH 状态的空连接。那么一台服务端机器上最大可以支持多少条 TCP 连接?这个连接数会受哪些因素的影响?

1、在不考虑连接上数据的收发和处理的情况下,仅考虑 ESTABLISH 状态下的空连接情况下,一台服务器上最大可支持的TCP连接数量基本上可以说是由内存大小来决定的。

2、四元组唯一确定一条连接,但服务端可以接收来自任意客户端的请求,所以根据这个理论计算出来的数字太大,没有实际意义。另外文件描述符限制其实也是内核为了防止某些应用程序不受限制的打开【文件句柄】而添加的限制。这个限制只要修改几个内核参数就可以加大。

3、一个 socket 大约消耗 3kb 左右的内存,这样真正制约服务端机器最大并发数的就是内存,拿一台 4GB 内存的服务器来说,可以支持的 TCP 连接数量大约是 100w+

3、一条客户端机器最大究竟能支持多少条连接

和服务端不同的是,客户端每次建立一条连接都需要消耗一个端口。在 TCP 协议中,端口是一个 2 字节的整数,因此范围只能是0~65535。那么客户单最大只能支持65535条连接吗?有没有办法突破这个限制,有的话有哪些办法?

1、客户度每次建立一条连接都需要消耗一个端口。从数字上来看,似乎最多只能建立 65535条连接。但实际上我们有两种办法破除65535这个限制

2、为客户端配置多 IP 方式二,分别连接不同的服务端

3、 所以一台 client发起百万条连接是没有任何问题的

4、做一个长连接推送产品,支持1亿用户需要多少台机器

假设你是系统架构师,现在老板给你一个需求,让你做一个类似友盟 upush 这样的产品。要在服务端机器上保持一个和客户端的长连接,绝大部分情况下连接都是空闲的,每天也就顶多推送两三次左右。总用户规模预计是1亿。那么现在请你来评估一下需要多少台服务器可以支撑这1亿条长连接。

1、对于长连接推送模块这种服务来说,给客户端发送数据只是偶尔的,一般一天也就顶多一两次。绝大部分情况下 TCP 连接都是空闲的,CPU 开销可以忽略

2、再基于内存来考虑,假设服务器内存是 128G 的,那么一台服务器可以考虑支持 500w 条并发。这样会消耗掉大约不到 20GB 内存用来保存这500w 条连接对应的 socket 。还剩下 100GB 以上的内存来应对接收、发送缓冲区等其他的开销足够了。所以,一亿用户,仅仅需要 20台服务器就差不多够用了!

ContactAuthor