一台服务器最大能支持多少条TCP连接?

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

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

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仅有一个IPserver端也仅有一个IP并且仅启动一个程序监听一个端口的情况下client端和这台server端最大可建立的连接条数就是 65535 个。

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

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

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

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

  • 【情况三】、如果一台client仅有一个IPserver端也仅有一个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 nofile、fs.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台服务器就差不多够用了

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: 服务器