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

1、约束参数

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

  • fs.file-max (体系等级参数):该参数描绘了整个体系能够翻开的最大文件数量。可是root用户不会受该参数约束(比方:现在整个体系翻开的文件描绘符数量已达到fs.file-max ,此时root用户仍然能够运用ps、kill等指令或翻开其他文件描绘符)
  • 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衔接,从根本上看其实便是client和server端在内存中保护的一组【socket内核方针】(这儿也对应着TCP四元组:源IP、源端口、方针IP、方针端口),他们只需能够找到对方,那么就算是一条衔接。那么一台服务器最大能树立多少条衔接呢?

  • 由于TCP衔接本质上能够了解为是client-server端的一对socket内核方针,那么从理论大将应该是【2^32 (ip数) * 2^16 (端口数)】条衔接(约等于两百多万亿)
  • 可是实际上由于受其他软硬件的影响,咱们一台服务器不或许能树立这么多衔接(首要是受CPU和内存约束)。

假如只以ESTABLISH状况的衔接来算(这些衔接仅仅树立,可是不收发数据也不处理相关的事务逻辑)那么一台服务器最大能树立多少衔接呢?以一台4GB内存的服务器为例!

  • 这种状况下,那么能树立的衔接数量首要取决于【内存的巨细】(由于假如是)ESTABLISH状况的闲暇衔接,不会耗费CPU(虽然有TCP保活包传输,但这个影响十分小,能够忽略不计)
  • 咱们知道一条ESTABLISH状况的衔接大约耗费【3.3KB内存】,那么经过核算得知一台4GB内存的服务器,【能够树立100w+的TCP衔接】(当然这儿仅仅核算全部的衔接都只树立衔接但不发送和处理数据的状况,假如真实场景中有数据来往和处理(数据接收和发送都需求恳求内存,数据处理便需求CPU),那便会耗费更高的内存以及占用更多的CPU,并发不或许达到100w+)

上面评论的都是进树立衔接的理想状况,在现实中假如有频频的数据收发和处理(比方:压缩、加密等),那么一台服务器能支撑1000衔接都算好的了,所以一台服务器能支撑多少衔接还要结合详细的场景去剖析,不能光靠理论值去算。抛开事务逻辑单纯的谈并发没有太大的实际意义

服务器的开支大头往往并不是衔接本身,而是每条衔接上的数据收发,以及恳求事务逻辑处理!!!

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

咱们知道客户端每和服务端树立一个衔接便会耗费掉client端一个端口。一台机器的端口规划是【0 ~ 65535】,那么是不是说一台client机器最多和一台服务端机器树立65535个衔接呢(这65535个端口里还有许多保存端口,可用端口或许只需64000个左右)?

由TCP衔接的四元组特性可知,只需四元组里某一个元素不同,那么就以为这是不同的TCP衔接。所以需求分状况评论:

  • 【状况一】、假如一台client仅有一个IP,server端也仅有一个IP而且仅发动一个程序,监听一个端口的状况下,client端和这台server端最大可树立的衔接条数便是 65535 个。
    • 由于源IP固定,方针IP和端口固定,四元组中唯一可变化的便是【源端口】,【源端口】的可用规划又是【0 ~ 65535】,所以一台client机器最大能树立65535个衔接
  • 【状况二】、假如一台client有多个IP(假定客户端有 n 个IP),server端仅有一个IP而且仅发动一个程序,监听一个端口的状况下,一台client机器最大能树立的衔接条数是:n * 65535
    • 由于方针IP和端口固定,有 n 个源IP,四元组中可变化的便是【源端口】+ 【源IP】,【源端口】的可用规划又是【0 ~ 65535】,所以一个IP最大能树立65535个衔接,那么n个IP最大就能树立 n * 65535个衔接了
    • 以现在的技术,给一个client分配多个IP是十分简单的事情,只需求去联系你们网管就能够做到。
  • 【状况三】、假如一台client仅有一个IP,server端也仅有一个IP可是server端发动多个程序,每个程序监听一个端口的状况下(比方server端发动了m个程序,监听了m个不同端口),一台client机器最大能树立的衔接数量为:65535 * m
    • 源IP固定,方针IP固定,方针端口数量为m个,可变化的是源端口,而源端口变化规划是【0 ~ 65535】,所以一台client机器最大能树立的TCP衔接数量是 65535 * m
  • 其余状况类推,可是客户端的可用端口规划一般达不到65535个,受内核参数net.ipv4.ip_local_port_range约束,假如要修正client所能运用的端口规划,能够修正这个内核参数的值。
  • 所以,不光是一台server端能够接收100w+个TCP衔接,一台client照样能发出100w+个衔接

四、其他

  • 三次握手里socket的全衔接行列长度由参数net.core.somaxconn来操控,默认巨细是128,当两台机器离的十分近,可是树立衔接的并发又十分高时,或许会导致半衔接行列或全衔接行列溢出,从而导致server端丢弃握手包。然后造成client超时重传握手包(至少1s今后才会重传),导致三次握手衔接树立耗时过长。咱们能够调整参数net.core.somaxconn来增加去按衔接行列的长度,从而减小丢包的影响

  • 有时分咱们经过 ctrl + c办法来终止了某个进程,可是当重启该进程的时分发现报错端口被占用,这种问题是由于【操作体系还没有来得及回收该端口,等一会儿重启运用就好了】

  • client程序在和server端树立衔接时,假如client没有调用bind办法传入指定的端口,那么client在和server端树立衔接的时分便会自己随机挑选一个端口来树立衔接。一旦咱们client程序调用了bind办法传入了指定的端口,那么client将会运用咱们bind里指定的端口来和server树立衔接。所以不主张client调用bind办法,bind函数会改动内核挑选端口的战略

    public static void main(String[] args) throws IOException {
        SocketChannel sc = SocketChannel.open();
      	// 客户端还能够调用bind办法
        sc.bind(new InetSocketAddress("localhost", 9999));
        sc.connect(new InetSocketAddress("localhost", 8080));
        System.out.println("waiting..........");
    }
    
  • 在Linux全部皆文件,当然也包括之前TCP衔接中说的socket。进程翻开一个socket的时分需求创建好几个内核方针,换一句直白的话说便是翻开文件方针吃内存,所以Linux体系基于安全视点考虑(比方:有用户进程歹意的翻开无数的文件描绘符,那不得把体系搞奔溃了),在多个方位都约束了可翻开的文件描绘符的数量

  • 内核是经过【hash表】的办法来办理全部现已树立好衔接的socket,以便于有恳求抵达时快速的经过【TCP四元组】查找到内核中对应的socket方针

    • 在epoll模型中,经过红黑树来办理epoll方针所办理的全部socket,用红黑树结构来平衡快速删除、插入、查找socket的功率

五、相关实际问题

在网络开发中,许多人对一个基础问题始终没有彻底搞了解,那便是一台机器最多能支撑多少条TCP衔接。不过由于客户端和服务端对端口运用办法不同,这个问题拆开来了解要简单一些。

留意,这儿说的是客户端和服务端都仅仅角色,并不是指某一台详细的机器。例如对于咱们自己开发的运用程序来说,当他呼应客户端恳求的时分,他便是服务端。当他向MySQL恳求数据的时分,他又变成了客户端。

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

你在线上或许遇到过too many open files这个错误,那么你了解这个报错发生的原理吗?假如让你修复这个错误,应该怎么处理呢?

  • 由于每翻开一个文件(包括socket),都需求耗费必定的内存资源。为了避免个别进程不受操控的翻开了过多文件而让整个服务器奔溃,Linux对翻开的文件描绘符数量有约束。假如你的进程触发到内核的约束,那么”too many open files” 报错就产生了
  • 能够经过修正fs.file-max soft nofilefs.nr_open这三个参数的值来修正进程能翻开的最大文件描绘符数量
    • 需求留意这三个参数之间的耦合联系!

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

由于这儿要考虑的是最大数,因而先不考虑衔接上的数据收发和处理,仅考虑ESTABLISH状况的空衔接。那么一台服务端机器上最大能够支撑多少条TCP衔接?这个衔接数会受哪些因素的影响?

  • 在不考虑衔接上数据的收发和处理的状况下,仅考虑ESTABLISH状况下的空衔接状况下,一台服务器上最大可支撑的TCP衔接数量基本上能够说是由内存巨细来决定的。
  • 四元组唯一确定一条衔接,但服务端能够接收来自任意客户端的恳求,所以根据这个理论核算出来的数字太大,没有实际意义。别的文件描绘符约束其实也是内核为了防止某些运用程序不受约束的翻开【文件句柄】而添加的约束。这个约束只需修正几个内核参数就能够加大。
  • 一个socket大约耗费3kb左右的内存,这样真正制约服务端机器最大并发数的便是内存,拿一台4GB内存的服务器来说,能够支撑的TCP衔接数量大约是100w+

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

和服务端不同的是,客户端每次树立一条衔接都需求耗费一个端口。在TCP协议中,端口是一个2字节的整数,因而规划只能是0~65535。那么客户单最大只能支撑65535条衔接吗?有没有办法打破这个约束,有的话有哪些办法?

  • 客户度每次树立一条衔接都需求耗费一个端口。从数字上来看,好像最多只能树立65535条衔接。但实际上咱们有两种办法破除65535这个约束
    • 办法一,为客户端装备多IP
    • 办法二,别离衔接不同的服务端
  • 所以一台client发起百万条衔接是没有任何问题的

4、做一个长衔接推送产品,支撑1亿用户需求多少台机器

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

  • 对于长衔接推送模块这种服务来说,给客户端发送数据仅仅偶然的,一般一天也就顶多一两次。绝大部分状况下TCP衔接都是闲暇的,CPU开支能够忽略
  • 再基于内存来考虑,加色服务器内存是128G的,那么一台服务器能够考虑支撑500w条并发。这样会耗费掉大约不到20GB内存用来保存这500w条衔接对应的socket。还剩余100GB以上的内存来应对接收、发送缓冲区等其他的开支足够了。所以,一亿用户,仅仅需求20台服务器就差不多够用了!

参阅书籍:《深入了解Linux网络》