玩转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是一 ...
随机推荐
- STM8驱动HX711
普及:HX711AD一款专为高精度电子秤而设计的 24 位 A/D 转换器芯片: 获取数据方法:两个普通IO DOUT输入:GPIO_Mode_In_FL_N ...
- tomcat 下部署单框架cas时,报出org.apache.jasper.JasperException异常的解决办法
在tomcat中部署好cas server(设置好https,将cas.war拷贝到了webapps下部署完成),启动tomcat后,访问http://localhost:8443/cas/login ...
- 蓝桥杯-买不到的数目-java
/* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2016, 广州科技贸易职业学院信息工程系学生 * All rights reserved. * 文件名称: ...
- MVC 5 + EF6 完整教程16 -- 控制器详解
Controller作为持久层和展现层的桥梁, 封装了应用程序的逻辑,是MVC中的核心组件之一. 本篇文章我们就来谈谈 Controller, 主要讨论两个方面: Controller运行机制简介 C ...
- 微信小程序,前端大梦想(五)
微信小程序之综合应用-访问网络加载数据 移动端访问网络加载数据时必不可少的功能,本章将接入豆瓣电影API,以列表的形式展现数据,支持下拉刷新及点击查看详情.重点包括: l 访问网络 l 跳转画面及传参 ...
- Xmind 体验分享
Xmind 8 体验 初识思维脑图 这两天在学习使用思维脑图(xmind是其中一款软件)ing,在体验了一把思维脑图的使用后,深深感受到了脑洞大开的魔力. 从昨晚开始研究使用,到今天晚上截止,自己试着 ...
- 广义后缀树(GST)算法的简介
导言 最近软件安全课上,讲病毒特征码的提取时,老师讲了一下GST算法.这里就做个小总结. 简介 基本信息 广义后缀树的英文为Generalized Suffix Tree,简称GST. 算法目的 ...
- MyBatis之级联——一对一关系
在学数据库概论的时候会听到这么几个词:数据库的关系分为一对一.一对多.多对多.对于在学校里学的知识已经忘得差不多了,在这里简单的提一下数据库的关系.此篇是介绍MyBatis是如何实现数据库中一对一关系 ...
- javascript之深入剖析this
this的重要性不言而喻,比如面试题经常考到,其次,如果彻底理解了this,那么对理解框架源码及编写高质量代码都有很大的帮助.本文就是要深入剖析this的几种情况,理解了原理,以后妈妈再也不用担心你的 ...
- 【JAVAWEB学习笔记】25_Linux基础
Linux基础 学习目标 1.了解Linux的简介与安装 2.掌握Linux常用的命令 3.掌握Linux系统上JDK.Mysql.Tomcat的安装 一.Linux的简介 1.Linux的概述 Li ...