玩转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是一 ...
随机推荐
- stm32中的延时函数
//粗延时函数,微秒 void delay_nus(u16 time) { u16 i=0; while(time--) { i=10; //自己定义 while(i--) ; } } //毫秒级的 ...
- 老司机带你开飞机 一: mssql on linux 安装指导
通常在本机开发环境中需要搭建所有的服务,还要修改本地的hosts,实在是不胜其烦.如今有了docker,完全不用污染本地环境,且看老司机带你搭建一个asp.net core的开发环境集群.愿你走出虚拟 ...
- MD5加密。
MD5 是把文件用open打开,然后对内容hash后的值,所以和文件名无关,和位置无关,和修改时间无关,只与文件内容有关.
- js 数字递增特效 仿支付宝我的财富 HTML5
上周五应着公司临时需求,一天的时间解决掉官网(ps:比较简单哈哈),需求里面有一个特效就是数字递增到指定的数值,其实JS写也不复杂的,但是我发现一个js小插件,这个插件轻巧简单,用起来也非常简单实用. ...
- JS判断当前手机类型
window.onload = function () { var u = navigator.userAgent; if (u.indexOf('Android') > -1 || u.ind ...
- ionic创建项目遇到的各种问题
前提:执行创建语句的前提是ionic环境已经装好,开始执行ionic start myApp blank. 提示已经有同名项目,是否覆盖.这里创建的是一个blank(空) 的ionic项目.还要两种是 ...
- IOS的控制器
控制器简单来说,就是用来做界面跳转的,类似于 Android 的Intent 1.创建一个控制器 控制器的常见的创建方式 )通过storyboard创建 //直接创建 NJViewController ...
- 使用HTMLParser爬取标签内容
以此网站为例 import urllib.request from html.parser import HTMLParser from html.entities import name2codep ...
- 用 Entity Framework结合Oracle数据库来开发项目
项目需要,要使用Oracle 11g数据库.作为不想写SQL的程序员,所以...... 原先想当然的是使用EF+MSSQL的方式来进行配置.吃了哑巴亏.然后谷歌出了一篇好文,沿着这篇文章进行了搭建,I ...
- 如何在Eclipse下查看JDK源代码
设置: 1.点 "窗口"-> "首选项" -> "Java" -> "已安装的JRE" 2.此时&qu ...