[译] 使用 Node.js 提供百万的活跃 WebSocket 连接

简介: 仅使用消费级笔记本和一些 Wifi 资源便可提供大量的 WebSocket 服务

原文地址: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 使用者尤其如此,所以为了演示我想在实际使用环境中开展大规模的测试。
我们计划使用我那购买了 6 年的笔记本电脑,它具有 8GB 运行内存和 72Mbit 速率的 Wifi 网络适配器(这是网络链接速度)的笔记本电脑。它还有一个 1Gbit 速率的以太网适配器,我们可以稍后使用。所有配置都是消费级的,在 2013 年购买后没有任何硬件升级。这个笔记本将运行安装了 uWebSockets.js v15.1.0 的 Node.js。

我们首先需要做一些 Linux 系统的配置工作 —— 主要是需要通过修改文件 /etc/security/limits.conf(在你的系统上文件路径可能不同,我这里用的是 Ubuntu 18.04 版本)来提升最大打开文件数量的限制。添加如下几行:

* soft nofile 1024000
* hard nofile 1024000

然后我们需要设置一些其他变量(同样的,你的路径可能不同):

sudo sysctl net.ipv4.tcp_tw_reuse=1
sudo sysctl fs.file-max=1024000

然后你需要需要配置某一网段内的大约 50 个 IP 地址。对于我的 Wifi 适配器,我添加了这行配置:

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 百万)。

然后我使用命令 sudo -i 将 web 服务以 root 身份运行,这之后执行 ulimit -n 1024000 命令,接着对 node examples/WebSocket.js(在 uWebSockets.js 文件夹中)也这么做。

真得就是这样的。客户端侧做了类似的配置,但是显然不需要设置多个 IP 地址。客户端电脑运行一个由 uSockets 编写的单线程 C 客户端。这个测试的源代码都是开源的,同时客户端的代码是位于 uWebSockets/benchmarks 文件夹的『scale_test.c』。你可能需要为你自己的运行做一些小改动。

WebSocket 连接数量需要花几分钟才能达到 100 万个,如果我们想做的改进的话可以增加每批次的连接数和使用多个线程的客户端(诸如此类),但是这与我们对服务端感兴趣的点无关。服务端运行在单个线程上并且在连接阶段或之后 CPU 占用率都很低。

image.png

首先,让我们讨论一下 5k 个关闭的连接。uWebSockets.js 被配置为丢弃和杀死所有闲置已超过 60s 的 WebSocket 连接。『idleTimeout』就被用到了,这意味着我们需要在每 60s 就要与每 100 万个 WebSocket 连接主动发送和接收一条 WebSocket 消息。

你可以在这上面这张网络图中看到与 ping 消息相关的流量峰值。每秒最少有 16.7k 条 WebSocket 消息需要到达服务器 —— 都变少了之后我们开始关闭连接。

显然我们通过 Wifi 网络没有很好地满足这个标准。我们是丢失了一些连接,但在一个没有花哨配置的 WiFi 网络环境下仍存活 995k 个 WebSocket 连接却是很酷的事情!

image.png

服务端的 CPU 使用率保持在 0–2% 范围,用户控空间内存使用大约为 500MB 而整体系统范围的内存使用大约为 4.7GB。CPU 使用率或者内存使用一直都没有出现服务端激增走势,它始终处于完全稳定状态。
好吧!那么让我们拿出大杀器吧 —— Ethernet。我们将服务器和客户端连接到 1Gbit 消费级路由器并重新运行测试:
image.png

结果是服务运行状况稳定,而且没有连接丢失,WiFi 网络稳定性不足但是 Ethernet 却表现很好。为了保证每项都是稳定的,我让客户端和服务器持续运行了一个小时,这样没有一个连接丢失,然后有约 1.2 亿条 WebSocket 消息(16.7k 60 60 * 2):

image.png

每项都是稳定良好运行。事实上,我在运行服务的笔记本上写着本文,并且被关闭的 socket 连接数量始终为 0,同时系统也是响应及时的。甚至我开启一个简单的游戏的情况下服务还能让连接继续。
此时我们已经实现了一个非常酷的概念验证场景。有一部分归因于稳定的 Ethernet 连接,但当然很大程度上也依赖服务端软件。任何其他的 Node.js 软件栈都无法实现这一壮举 —— 它们都不具备像这样足以在笔记本上维持这么多 WebSocket 连接的轻量级和高性能特点。你可以在系统变得无响应时停止 swap 分区交换,并且下面看到的这样来停止获取 ping 结果:

image.png

使用 uWebSockets.js,我们可以在这台笔记本上运行几十万个 WebSocket 连接,但是超过 100 万的常规连接则需要重新编译具备不同限制的 Linux 内核,这也是我们把它作为边界值的原因。

这里我们不打算去研究底层的嵌入式 C 开发,并且我认为这是明智的选择。只需启动一个新应用实例,一台新笔记本,通过这种方式继续扩展你的问题。

如果你对这个软件栈感兴趣,有 I/O 扩展性问题,或者想要避免陷入许多常见陷阱,一定要联系我们,我们可以通过公司对公司的形式来研讨问题。
感谢你的阅读!


作者:Mirosalva
链接:https://juejin.im/post/5cbeb2f45188250ab65f1d0c
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

目录
相关文章
|
12天前
|
JavaScript 前端开发 网络协议
Vue.js 与 WebSocket 的惊世联姻!实时数据通信的震撼变革,你敢错过?
【8月更文挑战第30天】在现代Web开发中,实时数据通信至关重要。Vue.js作为流行前端框架,结合WebSocket技术,实现了高效实时的数据交互。本文简要介绍了WebSocket原理及其在Vue.js项目中的应用方法,包括建立连接、监听事件及数据处理等步骤,展示了如何利用二者结合轻松应对实时聊天、股票更新等多种场景,为开发者提供了实用指南。希望本文能帮助您更高效地实现Web应用的实时通信功能。
59 0
|
3月前
|
JavaScript 网络协议 前端开发
【Nodejs】WebSocket 全面解析+实战演练——(Nodejs实现简易聊天室)
【Nodejs】WebSocket 全面解析+实战演练——(Nodejs实现简易聊天室)
316 0
|
17天前
|
JavaScript 关系型数据库 MySQL
node连接mysql,并实现增删改查功能
【8月更文挑战第26天】node连接mysql,并实现增删改查功能
32 3
|
15天前
|
JavaScript NoSQL 前端开发
|
2月前
|
JavaScript 关系型数据库 API
Nest.js 实战 (二):如何使用 Prisma 和连接 PostgreSQL 数据库
这篇文章介绍了什么是Prisma以及如何在Node.js和TypeScript后端应用中使用它。Prisma是一个开源的下一代ORM,包含PrismaClient、PrismaMigrate、PrismaStudio等部分。文章详细叙述了安装PrismaCLI和依赖包、初始化Prisma、连接数据库、定义Prisma模型、创建Prisma模块的过程,并对比了Prisma和Sequelize在Nest.js中的使用体验,认为Prisma更加便捷高效,没有繁琐的配置。
Nest.js 实战 (二):如何使用 Prisma 和连接 PostgreSQL 数据库
|
30天前
|
JavaScript 前端开发 网络协议
抖音直播弹幕数据逆向:websocket和JS注入
抖音直播弹幕数据逆向:websocket和JS注入
114 1
|
22天前
|
关系型数据库 Serverless API
Serverless 函数实例问题之websocket连接如何解决
除了控制台,您还可以通过API或CLI使用PolarDB实例的Exec功能。API接口允许执行数据库命令,而阿里云CLI工具如`aliyun polardb`命令可用于管理数据库实例。详情参见[文档](https://help.aliyun.com/document_detail/137999.html)。
36 0
|
28天前
|
JavaScript 前端开发 应用服务中间件
【qkl】JavaScript连接web3钱包,实现测试网络中的 Sepolia ETH余额查询、转账功能
【区块链】JavaScript连接web3钱包,实现测试网络中的 Sepolia ETH余额查询、转账功能
若依修改,若依部署在本地运行时的注意事项,后端连接了服务器,本地的vue.config.js要先改成localhost:端口号与后端匹配,部署的时候再改公网IP:端口号
若依修改,若依部署在本地运行时的注意事项,后端连接了服务器,本地的vue.config.js要先改成localhost:端口号与后端匹配,部署的时候再改公网IP:端口号
|
2月前
|
前端开发 NoSQL 数据库
部署常用的流程,可以用后端,连接宝塔,将IP地址修改好,本地只要连接好了,在本地上前后端跑起来,前端能够跑起来,改好了config.js资料,后端修改好数据库和连接redis,本地上跑成功了,再改
部署常用的流程,可以用后端,连接宝塔,将IP地址修改好,本地只要连接好了,在本地上前后端跑起来,前端能够跑起来,改好了config.js资料,后端修改好数据库和连接redis,本地上跑成功了,再改