前言:

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单机多核集群(多进程)的更多相关文章

  1. 运行一个nodejs服务,先发布为deployment,然后创建service,让集群外可以访问

    问题来源 海口-老男人 17:42:43 就是我要运行一个nodejs服务,先发布为deployment,然后创建service,让集群外可以访问 旧报纸 17:43:35 也就是 你的需求为 一个a ...

  2. Redis总结(五)缓存雪崩和缓存穿透等问题 Web API系列(三)统一异常处理 C#总结(一)AutoResetEvent的使用介绍(用AutoResetEvent实现同步) C#总结(二)事件Event 介绍总结 C#总结(三)DataGridView增加全选列 Web API系列(二)接口安全和参数校验 RabbitMQ学习系列(六): RabbitMQ 高可用集群

    Redis总结(五)缓存雪崩和缓存穿透等问题   前面讲过一些redis 缓存的使用和数据持久化.感兴趣的朋友可以看看之前的文章,http://www.cnblogs.com/zhangweizhon ...

  3. Centos7.5基于MySQL5.7的 InnoDB Cluster 多节点高可用集群环境部署记录

    一.   MySQL InnoDB Cluster 介绍MySQL的高可用架构无论是社区还是官方,一直在技术上进行探索,这么多年提出了多种解决方案,比如MMM, MHA, NDB Cluster, G ...

  4. Kubernetes1.91(K8s)安装部署过程(三)--创建高可用etcd集群

    这里的etcd集群复用我们测试的3个节点,3个node都要安装并启动,注意修改配置文件 1.TLS认证文件分发:etcd集群认证用,除了本机有,分发到其他node节点 scp ca.pem kuber ...

  5. 实现Redis Cluster并实现Python链接集群

    目录 一.Redis Cluster简单介绍 二.背景 三.环境准备 3.1 主机环境 3.2 主机规划 四.部署Redis 4.1 安装Redis软件 4.2 编辑Redis配置文件 4.3 启动R ...

  6. wsl2 ubuntu20.04 上使用 kubeadm 创建一个单主集群

    wsl2 ubuntu20.04 上使用 kubeadm 创建一个单主集群 官方文档使用 kubeadm 创建一个单主集群 环境初始化 建议尽可能初始化环境,命令wsl --unregister Ub ...

  7. springCloud系列教程01:Eureka 注册中心集群搭建

    springCloud系列教程包含如下内容: springCloud系列教程01:Eureka 注册中心集群搭建 springCloud系列教程02:ConfigServer 配置中心server搭建 ...

  8. 使用Vagrant创建多节点虚拟机集群

    摘要: 在前一篇博客中,我介绍了使用Vagrant快速创建虚拟机,但是所创建的只是单个虚拟机.这篇博客将介绍使用Vagrant创建多节点虚拟机集群,可以作为Hadoop,Spark以及Storm等分布 ...

  9. nodejs的mysql模块学习(九)连接池集群

    连接池集群 连接池集群可以提供多个主机连接 创建连接池集群 //创建连接池集群 var poolCluster = mysql.createPoolCluster(); //添加配置 config是一 ...

随机推荐

  1. Nodejs进阶:MD5入门介绍及crypto模块的应用

    本文摘录自<Nodejs学习笔记>,更多章节及更新,请访问 github主页地址.欢迎加群交流,群号 197339705. 简介 MD5(Message-Digest Algorithm) ...

  2. angular 实现时间段选择组件

    前段时间公司有个后台项目需要使用一个选择时间段的组件,看了一下就自己写了一下,用angular写这种插件还是很简单的. 先看看最终是什么样子的: 功能是用户可以选择任意时间段,鼠标可以拖动任意的一周的 ...

  3. Java中的集合与线程的Demo

    一.简单线程同步问题 package com.ietree.multithread.sync; import java.util.Vector; public class Tickets { publ ...

  4. lxml简明教程

    最近要做下微信爬虫,之前写个小东西都是直接用正则提取数据就算了,如果需要更稳定的提取数据,还是使用 xpath 定位元素比较可靠.周末没事,从爬虫的角度研究了一下 python xml 相关的库. P ...

  5. python中str的find()

    今天学习语法的时候发现字符串自带函数find和操作符in功能十分近似,几乎一模一样 if 'a' in name:    print 'Yes, it contains the string &quo ...

  6. hdu1160dp

    https://vjudge.net/contest/68966#problem/J #include<map> #include<set> #include<list& ...

  7. webstorm html碎片整理功能

    我们用字符串形式写html模板时,或者向某标签添加html内容时,如下,如果这个str更加的长,一旦里面少了一个单引号,少了一个加号,基本报错还看不懂,一脸懵逼... // 假定后台传给我们的数据为 ...

  8. Python之函数知识

    Python函数分类 a,内置函数 b,自定义函数 c,导入函数 一个函数就相当于一个功能块,比如获取数据库,更新数据库,函数其实就是代码的分块,调用函数来执行代码块 一块就代表一个功能 内置函数有以 ...

  9. hdu1507 Uncle Tom's Inherited Land* 二分匹配

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1507 将i+j为奇数的构成x集合中 将i+j为偶数的构成y集合中 然后就是构建二部图 关键就是构图 然 ...

  10. C++ 常见的 Undefined symbols for architecture *

    出现 Undefined symbols for architecture x86_64: 的原因 1.函数申明了,却未被定义. 2.申明的虚函数未被实现. NOTE: a missing vtabl ...