前言:

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. Vue 事件驱动和依赖追踪

    之前关于 Vue 数据绑定原理的一点分析,最近需要回顾,就顺便发到随笔上了 在之前实现一个自己的Mvvm中,用 setter 来观测model,将界面上所有的 viewModel 绑定到 model ...

  2. C#网络程序设计(1)网络编程常识与C#常用特性

        网络程序设计能够帮我们了解联网应用的底层通信原理!     (1)网络编程常识: 1)什么是网络编程 只有主要实现进程(线程)相互通信和基本的网络应用原理性(协议)功能的程序,才能算是真正的网 ...

  3. [bug] Cannot proceed because system tables used by Event Scheduler were found damaged at server start

    本地:mac 10.12.3  mysql 5.6 远程:linux 7.3    mysql 5.7.18.  (远程数据库yum安装,又5.6升级到5.7) 步骤:从本地数据库导出数据到远程数据库 ...

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

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

  5. PhpMyAdmin导入数据库大小限制?

    问题描述: 在phpMyAdmin中导入数据库时,出现问题: 1. 如果按照扩展名.sql导入,提示如下: 没有接收到要导入的数据.可能是文件名没有提交,也可能是文件大小超出 PHP 限制. 2. 如 ...

  6. <JAVA>可变参数列表

    这是java1.5版本的新特性,就是当你想定义一个方法,但是不知道以后要用的时候传几个参数进去,这时可以在方法的参数列表中这样写(参数类型... 数组名),然后在方法内部直接用操作数组的方式操作.比如 ...

  7. C#使用NOPI导入Excel

    使用NOPI导入Excel文档 NOPI版本:2.3.0,依赖于NPOI的SharpZipLib版本:0.86,经测试适用于.net4.0+ 记录遇到的几个问题 NOPI中的IWorkbook接口:x ...

  8. 《分布式Java应用之基础与实践》读书笔记四

    Java代码作为一门跨操作系统的语言,最终是运行在JVM中的,所以对于JVM的理解就变得非常重要了.整体上,我们可以从三个方面来深入理解JVM. Java代码的执行 内存管理 线程资源同步和交互机制 ...

  9. WebSocket学习总结

    一 .websocket 已解决      但是websocket延伸出来的网络编程还有好多知识点没有清理.主要的流程和实现方式已经大概了解清楚,下面从学习的进度思路来一点点复习.        网络 ...

  10. HttpClient--HttpGet使用

    最近公司在做一个爬虫工具,爬取公司现网的数据,留给方通项目使用 用到里阿帕奇的这两个类,在网上看到了一些资料结合自己的应用,这个贴出一个demo import com.alibaba.fastjson ...