玩转nodeJS系列:使用cluster创建nodejs单机多核集群(多进程)
前言:
nodejs提供了cluster集群(支持端口共享的多进程),cluster基于child_process,process二次封装,方便我们使用该功能实现单机nodejs的web集群。
1、cluster的处理机制
都知道单线程的nodejs遇到cpu密集型操作会很容易出现CPU满载,服务阻塞的问题;通过类似nginx的master-worker多进程负载处理方式进一步压榨硬件性能,提升nodejs单机服务处理性能。
m a s t e r(主进程,分发请求)
| | | |
worker worker worker worker(子进程,处理请求)
2、官方cluster实现
nodejs官方文档中cluster的实现demo:
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
});
} else {
http.createServer((req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);
}
3、实现自己的单机nodejs集群,实现多进程端口共享
3.1、代码实现
//开启集群服务
var startClusterSever = function(port, numCPUs) {
if (cluster.isMaster) {
for (var i = 0; i < numCPUs; i++) {
const work = cluster.fork();
console.log(work.process.pid);
workers[i] = work;
}
cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
});
} else {
console.log(cluster.worker.id);
http.createServer((req, res) => {
console.log("子进程:" + cluster.worker.id + "正在处理请求...");
routeHandler(req, res);
}).listen(port); }
}
3.2、基于eguidRoute路由实现
注:在上一章的eguidRoute基础上增加开启单机集群功能
使用:
eguid.start(8081, 8);//监听8081端口,多线程数量8
const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs');
const cluster = require('cluster');
//路由表
var routeArr = {};
//进程列表
var workers = {};
//进程数量
var clusterNum;
//解析请求地址
var getPathName = function(reqUrl) {
var urlParse = getUrlParse(reqUrl);
return urlParse.pathname;
};
//获取url解析
var getUrlParse = function(reqUrl) {
return url.parse(reqUrl);
};
//是否是一个请求
var isFunc = function(pathName) {
return typeof routeArr[pathName] === 'function';
};
/**静态资源处理 param(req:请求,res:响应,pathName:路径) */
var resStatic = function(req, res, pathName) {
fs.readFile(pathName.substr(1), function(err, data) {
err ? endErrorReq(res, 501) : endStaticReq(res, pathName, data);
res.end();
});
};
//响应静态资源
var endStaticReq = function(res, pathName, data) {
var suffix = path.extname(pathName);
res.writeHead(200, { 'Content-Type': suffix === ".css" ? 'text/css' : 'text/html;' + 'charset=utf-8' });
res.write(data);
};
//结束错误请求
var endErrorReq = function(res, err) {
res.writeHead(err);
res.end();
};
/** 路由分发处理器 */
var routeHandler = function(req, res) {
var pathName = getPathName(req.url);
isFunc(pathName) ? routeArr[pathName](req, res, pathName) : resStatic(req, res, pathName);
console.log("处理了一个请求:" + pathName);
};
/** 添加动态路由解析
* param{
* reqUrl:请求地址,
* service:function(request:请求,response:响应,pathName:请求名)}
*/
var addDynamicRoute = function(reqUrl, service) {
console.log("添加的服务名:" + reqUrl);
routeArr[reqUrl] = service;
};
/** 开启服务器并监听端口 param{port:端口号}*/
var startServer = function(port, num) {
clusterNum = num;
if (num) {
startClusterSever(port, num);
} else {
//创建服务器
http.createServer(function(req, res) {
routeHandler(req, res);
}).listen(port); //注意这里的端口改成了变量
//开启后在控制台显示该服务正在运行
console.log('Server running at http://127.0.0.1:' + port);
}
};
/** 设置静态页面请求别名 param(newUrl:新的请求路径, oldUrl:原始路径) */
var setIndex = function(newUrl, oldUrl) {
addDynamicRoute(newUrl, function(req, res) {
resStatic(req, res, oldUrl);
});
};
/**自定义静态页面处理方式 staticHandlerService=function(req,res,pathName)*/
var setresStaticFunc = function(staticHandlerService) {
resStatic = staticHandlerService;
}; //开启集群服务
var startClusterSever = function(port, numCPUs) {
if (cluster.isMaster) {
for (var i = 0; i < numCPUs; i++) {
const work = cluster.fork();
console.log(work.process.pid);
workers[i] = work;
}
cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
});
} else {
console.log(cluster.worker.id);
http.createServer((req, res) => {
console.log("子进程:" + cluster.worker.id + "正在处理请求...");
routeHandler(req, res);
}).listen(port); }
}
exports.route = routeHandler;
exports.add = addDynamicRoute;
exports.start = startServer;
exports.index = setIndex;
exports.modStatic = setresStaticFunc;
/**
* eguidRouter快速灵活的路由
* 功能实现:
* 1、自动静态路由解析
* 2、支持手动设置静态路由别名
* 3、支持创建新的静态路由实现(方便加载模板)
* 4、动态路由解析
* 5、自动错误响应
* 6、使用原生API,无第三方框架
* 7、支持cluster单机集群(机器性能压榨机)
*/
玩转nodeJS系列:使用cluster创建nodejs单机多核集群(多进程)的更多相关文章
- 运行一个nodejs服务,先发布为deployment,然后创建service,让集群外可以访问
问题来源 海口-老男人 17:42:43 就是我要运行一个nodejs服务,先发布为deployment,然后创建service,让集群外可以访问 旧报纸 17:43:35 也就是 你的需求为 一个a ...
- Redis总结(五)缓存雪崩和缓存穿透等问题 Web API系列(三)统一异常处理 C#总结(一)AutoResetEvent的使用介绍(用AutoResetEvent实现同步) C#总结(二)事件Event 介绍总结 C#总结(三)DataGridView增加全选列 Web API系列(二)接口安全和参数校验 RabbitMQ学习系列(六): RabbitMQ 高可用集群
Redis总结(五)缓存雪崩和缓存穿透等问题 前面讲过一些redis 缓存的使用和数据持久化.感兴趣的朋友可以看看之前的文章,http://www.cnblogs.com/zhangweizhon ...
- Centos7.5基于MySQL5.7的 InnoDB Cluster 多节点高可用集群环境部署记录
一. MySQL InnoDB Cluster 介绍MySQL的高可用架构无论是社区还是官方,一直在技术上进行探索,这么多年提出了多种解决方案,比如MMM, MHA, NDB Cluster, G ...
- Kubernetes1.91(K8s)安装部署过程(三)--创建高可用etcd集群
这里的etcd集群复用我们测试的3个节点,3个node都要安装并启动,注意修改配置文件 1.TLS认证文件分发:etcd集群认证用,除了本机有,分发到其他node节点 scp ca.pem kuber ...
- 实现Redis Cluster并实现Python链接集群
目录 一.Redis Cluster简单介绍 二.背景 三.环境准备 3.1 主机环境 3.2 主机规划 四.部署Redis 4.1 安装Redis软件 4.2 编辑Redis配置文件 4.3 启动R ...
- wsl2 ubuntu20.04 上使用 kubeadm 创建一个单主集群
wsl2 ubuntu20.04 上使用 kubeadm 创建一个单主集群 官方文档使用 kubeadm 创建一个单主集群 环境初始化 建议尽可能初始化环境,命令wsl --unregister Ub ...
- springCloud系列教程01:Eureka 注册中心集群搭建
springCloud系列教程包含如下内容: springCloud系列教程01:Eureka 注册中心集群搭建 springCloud系列教程02:ConfigServer 配置中心server搭建 ...
- 使用Vagrant创建多节点虚拟机集群
摘要: 在前一篇博客中,我介绍了使用Vagrant快速创建虚拟机,但是所创建的只是单个虚拟机.这篇博客将介绍使用Vagrant创建多节点虚拟机集群,可以作为Hadoop,Spark以及Storm等分布 ...
- nodejs的mysql模块学习(九)连接池集群
连接池集群 连接池集群可以提供多个主机连接 创建连接池集群 //创建连接池集群 var poolCluster = mysql.createPoolCluster(); //添加配置 config是一 ...
随机推荐
- Nodejs进阶:MD5入门介绍及crypto模块的应用
本文摘录自<Nodejs学习笔记>,更多章节及更新,请访问 github主页地址.欢迎加群交流,群号 197339705. 简介 MD5(Message-Digest Algorithm) ...
- angular 实现时间段选择组件
前段时间公司有个后台项目需要使用一个选择时间段的组件,看了一下就自己写了一下,用angular写这种插件还是很简单的. 先看看最终是什么样子的: 功能是用户可以选择任意时间段,鼠标可以拖动任意的一周的 ...
- Java中的集合与线程的Demo
一.简单线程同步问题 package com.ietree.multithread.sync; import java.util.Vector; public class Tickets { publ ...
- lxml简明教程
最近要做下微信爬虫,之前写个小东西都是直接用正则提取数据就算了,如果需要更稳定的提取数据,还是使用 xpath 定位元素比较可靠.周末没事,从爬虫的角度研究了一下 python xml 相关的库. P ...
- python中str的find()
今天学习语法的时候发现字符串自带函数find和操作符in功能十分近似,几乎一模一样 if 'a' in name: print 'Yes, it contains the string &quo ...
- hdu1160dp
https://vjudge.net/contest/68966#problem/J #include<map> #include<set> #include<list& ...
- webstorm html碎片整理功能
我们用字符串形式写html模板时,或者向某标签添加html内容时,如下,如果这个str更加的长,一旦里面少了一个单引号,少了一个加号,基本报错还看不懂,一脸懵逼... // 假定后台传给我们的数据为 ...
- Python之函数知识
Python函数分类 a,内置函数 b,自定义函数 c,导入函数 一个函数就相当于一个功能块,比如获取数据库,更新数据库,函数其实就是代码的分块,调用函数来执行代码块 一块就代表一个功能 内置函数有以 ...
- hdu1507 Uncle Tom's Inherited Land* 二分匹配
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1507 将i+j为奇数的构成x集合中 将i+j为偶数的构成y集合中 然后就是构建二部图 关键就是构图 然 ...
- C++ 常见的 Undefined symbols for architecture *
出现 Undefined symbols for architecture x86_64: 的原因 1.函数申明了,却未被定义. 2.申明的虚函数未被实现. NOTE: a missing vtabl ...