首先在服务端输入命令, 看一下单个进程所能支持的最大句柄数。
sh ulimit -n
输入命令后, 会出现 1 024 的数字, 表示 Linux 系统中一个进程能够打开的最大文件数, 由于开启一个 TCP 连接就会在 Linux 系统中对应创建一个文件, 所以就是受这个文件的最大文件数限制。那为什么前面演示的服务端连接数最终定格在 870, 比 1 024 小呢? 其实是因为除了连接数, 还有 JVM 打开的文件 Class 类也算作进程内打开的文件, 所以, 1 024 减去 JVM 打开的文件数剩下的就是 TCP 所能支持的连接数。接下来想办法突破这个限制, 首先在服务器命令行输入以下命令, 打开 /etc/security/limits.conf
文件。
sh sudo vi /etc/security/limits.conf
然后在这个文件末尾加上下面两行代码。
```sh
*
表示当前用户, hard 和 soft 分别表示限制和警告限制, nofile 表示最大的文件数标识, 后面的数字 1 000 000 表示任何用户都能打开 100 万个文件, 这也是操作系统所能支持的最大值, 如下图所示。接下来, 输入以下命令。
sh ulimit -n
这时候, 我们发现还是 1 024, 没变, 重启服务器。将服务端程序和客户端程序分别重新运行, 这时候只需静静地观察连接数的变化, 最终连接数停留在 137 920, 同时抛出了异常, 如下所示。
当前客户端连接数: 137920
Exception in thread “nioEventLoopGroup-2-1” java.lang.InternalError: java.io.FileNotFoundException: /usr/java/jdk1.8.0_121/jre/lib/ext/cldrdata.jar (Too many open files)
…
这又是为什么呢? 肯定还有地方限制了连接数, 想要突破这个限制, 就需要突破全局文件句柄数的限制。
首先在 Linux 命令行输入以下命令, 可以查看 Linux 系统所有用户进程所能打开的文件数。
sh cat /proc/sys/fs/file-max
通过上面这个命令可以看到全局的限制, 发现得到的结果是 10 000。可想而知, 局部文件句柄数不能大于全局的文件句柄数。所以, 必须将全局的文件句柄数限制调大, 突破这个限制。首先切换为 ROOT 用户, 不然没有权限。
sh sudo -s echo 2000> /proc/sys/fs/file-max exit
我们改成 20 000 来测试一下, 继续试验。分别启动服务端程序和客户端程序, 发现连接数已经超出了 20 000 的限制。
前面使用 echo 来配置 /proc/sys/fs/file-max
的话, 重启服务器就会失效, 还会变回原来的 10 000, 因此, 直接用 vi 命令修改, 输入以下命令行。
sh sodu vi /etc/sysctl.conf
在 /etc/sysctl.conf
文件末尾加上下面的内容。
sh fs.file-max=1000000
结果如下图所示。
接下来重启 Linux 服务器, 再启动服务端程序和客户端程序。
sh 当前客户端连接数: 9812451 当前客户端连接数: 9812462 当前客户端连接数: 9812489 当前客户端连接数: 9812501 当前客户端连接数: 9812503 ...
最终连接数定格在 98 万左右。我们发现主要受限于本机本身的性能。用 htop
命令查看一下, 发现 CPU 都接近 100%, 如下图所示。
以上是操作系统层面的调优和性能提升