Nodejs如何让node.js充分利用多核服务器的性能
Nodejs如何让node.js充分利用多核服务器的性能
之前和PHP同事讨论node.js的性能问题,看了一些node.js的相关文档,node.js除了拥有非阻塞I/O,快速开发等诸多优点外,其缺点也很明显:
node server.js
node server0.js
ps -ef | grep node (用来查看node的进程号)
root 19277 2517 15 10:12 pts/1 00:00:20 node /usr/local/node/src/chating_express/server.js
root 19283 2566 18 10:13 pts/2 00:00:20 node /usr/local/node/src/chating_express/server0.js
root 19291 2384 0 10:15 pts/0 00:00:00 grep node
taskset -pc 0 19277 (其中0代表CPU0,以此类推)
pid 19277’s current affinity list: 0,1
pid 19277’s new affinity list: 0
upstream node_server_pool {
server 10.1.1.202:8888 max_fails=1;
server 10.1.1.202:8889 max_fails=1;
}
server
{
listen 80;
server_name 10.1.1.202;
location /
{
proxy_pass http://node_server_pool;
proxy_set_header Host 10.1.1.202:80;
proxy_set_header X-Forwarded-For $remote_addr;
}
我想问下 如果不用taskset,测试的效果是怎样的呢。
Nodejs如何让Node.js充分利用多核服务器的性能
在讨论Node.js性能问题时,虽然Node.js以其非阻塞I/O和快速开发著称,但也存在一些明显的局限性:
- 单进程,只支持单核CPU:这意味着Node.js默认只能利用一个核心的计算能力。
- 单进程,一旦崩溃会导致整个Web服务崩溃:虽然可以通过提高代码的健壮性来缓解这个问题。
开发环境
- VMware Red Hat 虚拟机
- CPU:两个
- 内存:1GB
实现思路
为了充分利用多核服务器的性能,我们可以采取以下几种策略:
- 多进程部署:通过创建多个Node.js进程,每个进程绑定到不同的CPU核心,从而实现负载均衡。
- 使用Nginx作为反向代理和负载均衡器:将请求分发到不同的Node.js实例,以平衡负载。
示例代码
假设我们有两个Node.js实例,分别监听不同的端口:
// server.js
const http = require('http');
const hostname = '127.0.0.1';
const port = 8888;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello from Server 1\n');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
// server0.js
const http = require('http');
const hostname = '127.0.0.1';
const port = 8889;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello from Server 2\n');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
绑定CPU核心
在Linux系统中,可以使用taskset
命令将每个Node.js进程绑定到特定的核心。例如:
# 查找Node.js进程ID
ps -ef | grep node
# 绑定进程到CPU核心
taskset -pc 0 <PID_1>
taskset -pc 1 <PID_2>
配置Nginx作为反向代理
编辑Nginx配置文件,添加以下内容:
upstream node_server_pool {
server 127.0.0.1:8888;
server 127.0.0.1:8889;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://node_server_pool;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
测试与验证
使用webbench
工具进行压力测试,并通过top
命令监控CPU使用情况。确保两个Node.js实例分布在不同的CPU核心上。
总结
通过多进程部署和使用Nginx作为反向代理,我们可以有效利用多核服务器的性能,提高系统的稳定性和响应速度。同时,确保数据共享(如Session)的一致性也非常重要,可以考虑使用Redis等外部存储服务。
感谢jackson的关注,今天忙活了一天,终于把压力测试结果写出来了,已经提交审批了。感谢继续关注! <br/>大体结果性能提升在15%-20%左右,当然稳定更有保障了。
[@snoopy](/user/snoopy) <br/>都关心到进程和cpu了,老卵
聊天室的代码可以开源吗?
最后补充一下:大家比较关心的开多进程和单开性能对比,由于之后提交的压力测试结果文章一直没有被审核通过,我这里说一下: <br/>裸框架:单进程node.js和多进程node.js几乎差不多,多进程大约提升5%-10% <br/>业务处理压力:我是模拟18万次的循环浮点计算,多进程比单进程性能提升大约100%,用户响应速度提升200%,极限负载也要提升50%。 <br/>具体压测结果见:http://snoopyxdy.blog.163.com/blog/static/6011744020117315192204/
[@hymnfish](/user/hymnfish), <br/>聊天室的代码是学习用的,写的真的很一般,等我整理下,下周放到github上去把。
等待博主把这个聊天室的github地址中。。。
[@hymnfish](/user/hymnfish) <br/>[@xiongjiabin](/user/xiongjiabin) <br/>最近空了些,聊天室代码和演示都在: <br/>http://spout.cnodejs.net/
感谢[@alsotang](/user/alsotang) ,cnode 开启 html,兼容老帖
[@fengmk2](/user/fengmk2) 应该的。。应该的。。
Node.js进程间的内存不能共享是个巨大的遗憾。
这个是nginx做,不用 cluster ?
我擦,竟是四年前的帖子
好文。
为了充分利用多核服务器的性能,Node.js 可以通过集群模块(cluster
)来创建子进程,每个子进程可以运行在不同的 CPU 上,从而实现负载均衡和提高性能。以下是一个简单的示例代码来展示如何使用 Node.js 的 cluster
模块。
示例代码
const cluster = require('cluster');
const os = require('os');
if (cluster.isMaster) {
console.log(`主进程 ${process.pid} 正在运行`);
// 计算可用的 CPU 核心数量
const numCPUs = os.cpus().length;
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`工作进程 ${worker.process.pid} 已退出`);
});
} else {
// 这里是每个子进程将要运行的代码
console.log(`工作进程 ${process.pid} 正在运行`);
// 示例 HTTP 服务器
const http = require('http');
const PORT = process.env.PORT || 8000;
http.createServer((req, res) => {
res.writeHead(200);
res.end('Hello World\n');
}).listen(PORT);
console.log(`HTTP 服务器正在监听端口 ${PORT}`);
}
解释
-
主进程 (
cluster.isMaster
):- 主进程负责生成子进程。
- 使用
os.cpus().length
来获取当前系统的 CPU 核心数量。 - 通过
cluster.fork()
方法创建指定数量的子进程。
-
子进程 (
!cluster.isMaster
):- 子进程运行实际的业务逻辑。
- 在这个例子中,子进程运行一个简单的 HTTP 服务器。
如何运行
- 将上述代码保存到一个文件,例如
cluster-server.js
。 - 使用命令行运行该文件:
node cluster-server.js
- 你可以使用
ps
命令查看当前运行的进程,并确认它们是否在不同的 CPU 核心上运行。
绑定 CPU 核心
如果你希望进一步绑定特定的 CPU 核心,可以使用 taskset
命令。例如,将第一个子进程绑定到 CPU 0,第二个子进程绑定到 CPU 1:
taskset -c 0,1 node cluster-server.js
这样,你可以确保每个子进程都在不同的 CPU 核心上运行,从而更好地利用多核服务器的性能。