Nodejs长连接高并发问题,很有挑战,大家来讨论下
Nodejs长连接高并发问题,很有挑战,大家来讨论下
At the first time, I used “express” module, with which I could reach about 120k concurrent connections
express有这么强吗
Node.js 长连接高并发问题,很有挑战,大家来讨论下
在现代Web应用中,处理高并发和长连接是一个常见的挑战。最近我尝试使用Express模块来处理这种情况,结果发现我可以达到大约12万的并发连接数。这让我感到非常惊讶,因为通常情况下,Express并不是专门设计用于处理这种级别的并发连接的。
为什么会出现这种情况?
首先,我们需要理解Express模块本身并不是为高并发而设计的。Express主要是作为一个轻量级的路由中间件,用于构建Web应用程序或API。然而,在某些情况下,它可能能够处理大量的并发连接,这取决于服务器硬件、网络配置以及代码优化等多种因素。
示例代码
以下是一个简单的Express应用示例,展示了如何设置一个基本的HTTP服务器:
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello World!');
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
如何优化高并发和长连接?
-
使用集群模式:Node.js内置了
cluster
模块,可以用来创建多个工作进程来处理请求。这样可以充分利用多核CPU的能力。const cluster = require('cluster'); const http = require('http'); const numCPUs = require('os').cpus().length; if (cluster.isMaster) { console.log(`Master ${process.pid} is running`); // Fork workers. for (let i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('exit', (worker, code, signal) => { console.log(`Worker ${worker.process.pid} died`); }); } else { // Workers can share any TCP connection // In this case it is an HTTP server http.createServer((req, res) => { res.writeHead(200); res.end('hello world\n'); }).listen(8000); console.log(`Worker ${process.pid} started`); }
-
使用反向代理:Nginx或Apache等反向代理服务器可以在前端处理静态文件请求,并将动态请求转发给Node.js服务器,从而减轻Node.js服务器的压力。
-
异步编程:确保你的代码是高度异步的,避免阻塞操作,例如数据库查询或文件I/O操作。
-
使用更高效的中间件:一些专门为高并发设计的中间件,如
fastify
或hapi
,可能会提供更好的性能。 -
负载均衡:通过在多个服务器之间分配请求,可以进一步提高系统的吞吐量和可靠性。
希望这些方法能帮助你更好地处理Node.js中的高并发和长连接问题。如果你有任何其他建议或经验分享,欢迎在评论区留言讨论!
120k这个也不是很准,因为我没有响应数据,后面测试发现开始相应请求后,每个连接会多占4k内存的样子,我猜跟socket send buffer有关,但是调整net.ipv4.tcp_wmem不起任何作用。另外express就是在原生http模块上封装了一些东西(比如在req、res上挂一些属性),肯定会多占一些内存,但是也不至于太多。
每人8K就是1000人在线需要8M,1W在线80M左右。
每人12KB万人在线也就消耗120M左右
很好奇LZ是什么史诗级应用, 顶级游戏服务器也不过为1W人左右并发连接设计
i5以上的CPU每核也就够NODE消耗1000个左右的并发响应, 超过这个数单是上下文切换就够它受的了,LZ还是先不要考虑内存的问题吧
纯粹用来推消息的应用,整个集群需要支撑千万级的用户量,所以单机并发量自然越高越好,可以省点机器。
实际上大部分连接大部分时候都会空闲,只占内存,所以我目前不是很担心CPU,想着先把内存占用优化到极致,再考虑推送消息的速率(CPU、网速等因素)。另外,也是好奇,极致能做到多少?在考虑这个问题的过程中也学到了不少东西,但是现在感觉卡住了。。。
i5以上的CPU每核也就够NODE消耗1000个左右的并发响应,超过这个数单是上下文切换就够它受的了
请问这个数据是怎么来得呢,node.js的上下文切换具体是指什么意思,谢谢!
nodejs是单线程的,不存在上下文切换,楼主的思路是对的,应该从消耗内存入手 ,我猜你目前要做的是网关服务器,只负责维护大量socket长链接,做消息转发,这样的话最好不要用express,它加那些东西没必要,另外,记得设置socket的两个属性,socket.setTimeout(0);socket.setNoDelay(true);这样内存消耗最少,实时性好,但是通信效率低一些,多个tcp packet不会组合成一个发送。如果真的是长链接,做游戏服务器,推荐ws,一个高效率的websocket实现,性能很好,我们也在用它做手游的服务端。
看到你发了代码? 另外发现这句: var res = new ServerResponse(socket);
完全没有必要用ServerResponse包装,你要写什么直接调用socket的write就好了,SR内部也会做buffer消耗你的内存。对了,kernel层面为你的每个socket消耗的内存你是很难优化了,默认的设置已经很合理,上面的socket.setTimeout(0);socket.setNoDelay(true);其实也是在设置该socket的内核handle参数了
你可以改变的是nodejs层面的东西,socket本身是继承自Stream接口的,Stream内存也有缓存,你想不用socket,直接使用handle也可以,在net模块里,self._handle.onconnection = onconnection;自己写onconnection,这个回调里每个连接进来你基本上就是得到一个socket handle,也就是对kernel socket handle的包装,直接用它好了
如果你还想再进一步,算了 哥们儿 你放弃nodejs,自己用c吧,用libev+mmap ,再进一步,你还可以写kernel driver,直接读写网卡硬件端口,再进一步。。。哥已经帮不了你了。。。
有意义嘛?
的确是类似网关的东西
socket默认就是没有超时和setNoDelay的
ws不太了解,一会看一下,谢谢!
ServerResponse这个是我自己定义的,里面封装了http响应头和Transfer-Encoding: chuned的处理,这样做是为了跟原生http模块保持一致。
直接使用handle
我以为在node.js层面net.Socket已经够底层了,看来不是,你说得方法值得一试。
自己用c吧,用libev+mmap
这个有空绝对要做一下看看
kernel driver,直接读写网卡硬件端口
这个就有点太底层了……目前没这个能力
有意义吗?
当然,可以了解到不少底层的东西。。。
谢谢你的建议!
v8是单线程的,不代表NODE就是单线程的,之所以NODE不是单线程的是因为其各种中间件模块的运作不是单线程的,例如MYSQL BINDING;当然会存在上下文切换
看了一下net.Socket的实现,觉得这个地方没办法省了,它上面挂的属性也不多,多数是方法,直接用handle的话差不多也要处理那么多东西。。。
node.js的单线程是指所有用户代码是在单线程中执行的是吧?我用pstree看node.js进程,显示这个:
node───2*[{node}]
这应该是两个线程吧?
想问一下,压测长连接的并发量,一般通过什么方法压比较靠谱?
我都是用node.js根据业务场景自己模拟客户端来测,长连接不像http,http是标准的,有很多开源工具(ab、siege)可以用。
楼主你好,我们做的应用和你这个类似,是连接网关的一个东西。目前我们是用java nio来实现的,我想问的是如果换成node来实现是不是代码会更简单,效率能更高些。
纯粹比效率java比node.js还是要高点的,不过java的gc比较难调,设得不好来次gc会有很长的延时。
用netty的话每个连接要占50k左右的内存。
我们做mqtt的长连接每个连接也要10k以上,用socket.io要更多,不过现在内存便宜, 觉得没必要做优化。 从实用的角度这样已经够用了, 不过研究一下底层确实可以学到不少东西,期待楼主的成果。
关于 Node.js 的长连接和高并发问题,确实是一个具有挑战性的主题。Node.js 本身是单线程的事件驱动模型,这使得它在处理高并发请求时表现出色。但是,当你需要处理长连接(如 WebSocket 或 HTTP 长轮询)时,情况可能会变得更加复杂。
示例代码:使用 ws
模块实现 WebSocket 长连接
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
console.log('A client connected!');
ws.on('message', function incoming(message) {
console.log('received: %s', message);
// 处理接收到的消息
});
ws.on('close', function close() {
console.log('A client disconnected!');
});
});
console.log('WebSocket server is running on ws://localhost:8080');
如何优化高并发场景
-
集群模式:使用 Node.js 的
cluster
模块来利用多核 CPU。这样可以将负载分发到多个子进程中。const cluster = require('cluster'); const http = require('http'); const numCPUs = require('os').cpus().length; if (cluster.isMaster) { for (let i = 0; i < numCPUs; i++) { cluster.fork(); } } else { const WebSocket = require('ws'); const wss = new WebSocket.Server({ port: 8080 }); wss.on('connection', function connection(ws) { // ... }); }
-
连接池:对于数据库操作,可以使用连接池来管理数据库连接,以避免频繁创建和销毁连接。
-
性能调优:通过使用
perf_hooks
模块进行性能分析,找出瓶颈并进行优化。 -
异步处理:确保所有的 I/O 操作都是异步的,避免阻塞事件循环。
-
负载均衡:使用反向代理服务器(如 Nginx 或 HAProxy)来进行负载均衡,以进一步分散请求压力。
这些策略可以帮助你更好地应对 Node.js 中的长连接和高并发问题。希望这些建议对你有所帮助!