- 原文地址:Millions of active WebSockets with Node.js
- 原文做者:Alex Hultman
- 译文出自:掘金翻译计划
- 本文永久连接:github.com/xitu/gold-m…
- 译者:Mirosalva
- 校对者:portandbridge,sunui
仅使用消费级笔记本和一些 Wifi 资源即可提供大量的 WebSocket 服务前端
经过最新发布的 TypeScript web 服务工程 uWebSockets.js,咱们看到它带来的不只有提高的性能,还有提高的内存利用率。对 Node.js 使用者尤为如此,因此为了演示我想在实际使用环境中开展大规模的测试。node
咱们计划使用我那购买了 6 年的笔记本电脑,它具备 8GB 运行内存和 72Mbit 速率的 Wifi 网络适配器(这是网络连接速度)的笔记本电脑。它还有一个 1Gbit 速率的以太网适配器,咱们能够稍后使用。全部配置都是消费级的,在 2013 年购买后没有任何硬件升级。这个笔记本将运行安装了 uWebSockets.js v15.1.0 的 Node.js。android
咱们首先须要作一些 Linux 系统的配置工做 —— 主要是须要经过修改文件 /etc/security/limits.conf(在你的系统上文件路径可能不一样,我这里用的是 Ubuntu 18.04 版本)来提高最大打开文件数量的限制。添加以下几行:ios
* soft nofile 1024000
* hard nofile 1024000
复制代码
而后咱们须要设置一些其余变量(一样的,你的路径可能不一样):git
sudo sysctl net.ipv4.tcp_tw_reuse=1
sudo sysctl fs.file-max=1024000
复制代码
而后你须要须要配置某一网段内的大约 50 个 IP 地址。对于个人 Wifi 适配器,我添加了这行配置:github
for i in {135..185}; do sudo ip addr add 192.168.0.$i/24 dev wlp3s0; done
复制代码
理论上,每一个 IP 地址有 65k 个链接限制,可是实际上限值常常大约在 20k 左右,因此咱们使用多个地址且使每一个地址支撑 20k 个链接数(50 * 20 千 = 1 百万)。web
而后我使用命令 sudo -i 将 web 服务以 root 身份运行,这以后执行 ulimit -n 1024000 命令,接着对 node examples/WebSocket.js(在 uWebSockets.js 文件夹中)也这么作。后端
真得就是这样的。客户端侧作了相似的配置,可是显然不须要设置多个 IP 地址。客户端电脑运行一个由 uSockets 编写的单线程 C 客户端。这个测试的源代码都是开源的,同时客户端的代码是位于 uWebSockets/benchmarks 文件夹的『scale_test.c』。你可能须要为你本身的运行作一些小改动。bash
WebSocket 链接数量须要花几分钟才能达到 100 万个,若是咱们想作的改进的话能够增长每批次的链接数和使用多个线程的客户端(诸如此类),可是这与咱们对服务端感兴趣的点无关。服务端运行在单个线程上而且在链接阶段或以后 CPU 占用率都很低。服务器
首先,让咱们讨论一下 5k 个关闭的链接。uWebSockets.js 被配置为丢弃和杀死全部闲置已超过 60s 的 WebSocket 链接。『idleTimeout』就被用到了,这意味着咱们须要在每 60s 就要与每 100 万个 WebSocket 链接主动发送和接收一条 WebSocket 消息。
你能够在这上面这张网络图中看到与 ping 消息相关的流量峰值。每秒最少有 16.7k 条 WebSocket 消息须要到达服务器 —— 都变少了以后咱们开始关闭链接。
显然咱们经过 Wifi 网络没有很好地知足这个标准。咱们是丢失了一些链接,但在一个没有花哨配置的 WiFi 网络环境下仍存活 995k 个 WebSocket 链接倒是很酷的事情!
服务端的 CPU 使用率保持在 0–2% 范围,用户控空间内存使用大约为 500MB 而总体系统范围的内存使用大约为 4.7GB。CPU 使用率或者内存使用一直都没有出现服务端激增走势,它始终处于彻底稳定状态。
好吧!那么让咱们拿出大杀器吧 —— Ethernet。咱们将服务器和客户端链接到 1Gbit 消费级路由器并从新运行测试:
结果是服务运行情况稳定,并且没有链接丢失,WiFi 网络稳定性不足可是 Ethernet 却表现很好。为了保证每项都是稳定的,我让客户端和服务器持续运行了一个小时,这样没有一个链接丢失,而后有约 1.2 亿条 WebSocket 消息(16.7k * 60 * 60 * 2):
每项都是稳定良好运行。事实上,我在运行服务的笔记本上写着本文,而且被关闭的 socket 链接数量始终为 0,同时系统也是响应及时的。甚至我开启一个简单的游戏的状况下服务还能让链接继续。
此时咱们已经实现了一个很是酷的概念验证场景。有一部分归因于稳定的 Ethernet 链接,但固然很大程度上也依赖服务端软件。任何其余的 Node.js 软件栈都没法实现这一壮举 —— 它们都不具有像这样足以在笔记本上维持这么多 WebSocket 链接的轻量级和高性能特色。你能够在系统变得无响应时中止 swap 分区交换,而且下面看到的这样来中止获取 ping 结果:
使用 uWebSockets.js,咱们能够在这台笔记本上运行几十万个 WebSocket 链接,可是超过 100 万的常规链接则须要从新编译具有不一样限制的 Linux 内核,这也是咱们把它做为边界值的缘由。
这里咱们不打算去研究底层的嵌入式 C 开发,而且我认为这是明智的选择。只需启动一个新应用实例,一台新笔记本,经过这种方式继续扩展你的问题。
若是你对这个软件栈感兴趣,有 I/O 扩展性问题,或者想要避免陷入许多常见陷阱,必定要联系咱们,咱们能够经过公司对公司的形式来研讨问题。
感谢你的阅读!
若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。