前言:

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:

  1. const cluster = require('cluster');
  2. const http = require('http');
  3. const numCPUs = require('os').cpus().length;
  4. if (cluster.isMaster) {
  5. for (var i = 0; i < numCPUs; i++) {
  6. cluster.fork();
  7. }
  8. cluster.on('exit', (worker, code, signal) => {
  9. console.log(`worker ${worker.process.pid} died`);
  10. });
  11. } else {
  12. http.createServer((req, res) => {
  13. res.writeHead(200);
  14. res.end('hello world\n');
  15. }).listen(8000);
  16. }

3、实现自己的单机nodejs集群,实现多进程端口共享

3.1、代码实现

  1. //开启集群服务
  2. var startClusterSever = function(port, numCPUs) {
  3. if (cluster.isMaster) {
  4. for (var i = 0; i < numCPUs; i++) {
  5. const work = cluster.fork();
  6. console.log(work.process.pid);
  7. workers[i] = work;
  8. }
  9. cluster.on('exit', (worker, code, signal) => {
  10. console.log(`worker ${worker.process.pid} died`);
  11. });
  12. } else {
  13. console.log(cluster.worker.id);
  14. http.createServer((req, res) => {
  15. console.log("子进程:" + cluster.worker.id + "正在处理请求...");
  16. routeHandler(req, res);
  17. }).listen(port);
  18.  
  19. }
  20. }

3.2、基于eguidRoute路由实现

注:在上一章的eguidRoute基础上增加开启单机集群功能

使用:

eguid.start(8081, 8);//监听8081端口,多线程数量8

  1. const http = require('http');
  2. const url = require('url');
  3. const path = require('path');
  4. const fs = require('fs');
  5. const cluster = require('cluster');
  6. //路由表
  7. var routeArr = {};
  8. //进程列表
  9. var workers = {};
  10. //进程数量
  11. var clusterNum;
  12. //解析请求地址
  13. var getPathName = function(reqUrl) {
  14. var urlParse = getUrlParse(reqUrl);
  15. return urlParse.pathname;
  16. };
  17. //获取url解析
  18. var getUrlParse = function(reqUrl) {
  19. return url.parse(reqUrl);
  20. };
  21. //是否是一个请求
  22. var isFunc = function(pathName) {
  23. return typeof routeArr[pathName] === 'function';
  24. };
  25. /**静态资源处理 param(req:请求,res:响应,pathName:路径) */
  26. var resStatic = function(req, res, pathName) {
  27. fs.readFile(pathName.substr(1), function(err, data) {
  28. err ? endErrorReq(res, 501) : endStaticReq(res, pathName, data);
  29. res.end();
  30. });
  31. };
  32. //响应静态资源
  33. var endStaticReq = function(res, pathName, data) {
  34. var suffix = path.extname(pathName);
  35. res.writeHead(200, { 'Content-Type': suffix === ".css" ? 'text/css' : 'text/html;' + 'charset=utf-8' });
  36. res.write(data);
  37. };
  38. //结束错误请求
  39. var endErrorReq = function(res, err) {
  40. res.writeHead(err);
  41. res.end();
  42. };
  43. /** 路由分发处理器 */
  44. var routeHandler = function(req, res) {
  45. var pathName = getPathName(req.url);
  46. isFunc(pathName) ? routeArr[pathName](req, res, pathName) : resStatic(req, res, pathName);
  47. console.log("处理了一个请求:" + pathName);
  48. };
  49. /** 添加动态路由解析
  50. * param{
  51. * reqUrl:请求地址,
  52. * service:function(request:请求,response:响应,pathName:请求名)}
  53. */
  54. var addDynamicRoute = function(reqUrl, service) {
  55. console.log("添加的服务名:" + reqUrl);
  56. routeArr[reqUrl] = service;
  57. };
  58. /** 开启服务器并监听端口 param{port:端口号}*/
  59. var startServer = function(port, num) {
  60. clusterNum = num;
  61. if (num) {
  62. startClusterSever(port, num);
  63. } else {
  64. //创建服务器
  65. http.createServer(function(req, res) {
  66. routeHandler(req, res);
  67. }).listen(port); //注意这里的端口改成了变量
  68. //开启后在控制台显示该服务正在运行
  69. console.log('Server running at http://127.0.0.1:' + port);
  70. }
  71. };
  72. /** 设置静态页面请求别名 param(newUrl:新的请求路径, oldUrl:原始路径) */
  73. var setIndex = function(newUrl, oldUrl) {
  74. addDynamicRoute(newUrl, function(req, res) {
  75. resStatic(req, res, oldUrl);
  76. });
  77. };
  78. /**自定义静态页面处理方式 staticHandlerService=function(req,res,pathName)*/
  79. var setresStaticFunc = function(staticHandlerService) {
  80. resStatic = staticHandlerService;
  81. };
  82.  
  83. //开启集群服务
  84. var startClusterSever = function(port, numCPUs) {
  85. if (cluster.isMaster) {
  86. for (var i = 0; i < numCPUs; i++) {
  87. const work = cluster.fork();
  88. console.log(work.process.pid);
  89. workers[i] = work;
  90. }
  91. cluster.on('exit', (worker, code, signal) => {
  92. console.log(`worker ${worker.process.pid} died`);
  93. });
  94. } else {
  95. console.log(cluster.worker.id);
  96. http.createServer((req, res) => {
  97. console.log("子进程:" + cluster.worker.id + "正在处理请求...");
  98. routeHandler(req, res);
  99. }).listen(port);
  100.  
  101. }
  102. }
  103. exports.route = routeHandler;
  104. exports.add = addDynamicRoute;
  105. exports.start = startServer;
  106. exports.index = setIndex;
  107. exports.modStatic = setresStaticFunc;
  108. /**
  109. * eguidRouter快速灵活的路由
  110. * 功能实现:
  111. * 1、自动静态路由解析
  112. * 2、支持手动设置静态路由别名
  113. * 3、支持创建新的静态路由实现(方便加载模板)
  114. * 4、动态路由解析
  115. * 5、自动错误响应
  116. * 6、使用原生API,无第三方框架
  117. * 7、支持cluster单机集群(机器性能压榨机)
  118. */

玩转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. stm32中的延时函数

    //粗延时函数,微秒 void delay_nus(u16 time) { u16 i=0; while(time--) { i=10;  //自己定义 while(i--) ; } } //毫秒级的 ...

  2. 老司机带你开飞机 一: mssql on linux 安装指导

    通常在本机开发环境中需要搭建所有的服务,还要修改本地的hosts,实在是不胜其烦.如今有了docker,完全不用污染本地环境,且看老司机带你搭建一个asp.net core的开发环境集群.愿你走出虚拟 ...

  3. MD5加密。

    MD5 是把文件用open打开,然后对内容hash后的值,所以和文件名无关,和位置无关,和修改时间无关,只与文件内容有关.

  4. js 数字递增特效 仿支付宝我的财富 HTML5

    上周五应着公司临时需求,一天的时间解决掉官网(ps:比较简单哈哈),需求里面有一个特效就是数字递增到指定的数值,其实JS写也不复杂的,但是我发现一个js小插件,这个插件轻巧简单,用起来也非常简单实用. ...

  5. JS判断当前手机类型

    window.onload = function () { var u = navigator.userAgent; if (u.indexOf('Android') > -1 || u.ind ...

  6. ionic创建项目遇到的各种问题

    前提:执行创建语句的前提是ionic环境已经装好,开始执行ionic start myApp blank. 提示已经有同名项目,是否覆盖.这里创建的是一个blank(空) 的ionic项目.还要两种是 ...

  7. IOS的控制器

    控制器简单来说,就是用来做界面跳转的,类似于 Android 的Intent 1.创建一个控制器 控制器的常见的创建方式 )通过storyboard创建 //直接创建 NJViewController ...

  8. 使用HTMLParser爬取标签内容

    以此网站为例 import urllib.request from html.parser import HTMLParser from html.entities import name2codep ...

  9. 用 Entity Framework结合Oracle数据库来开发项目

    项目需要,要使用Oracle 11g数据库.作为不想写SQL的程序员,所以...... 原先想当然的是使用EF+MSSQL的方式来进行配置.吃了哑巴亏.然后谷歌出了一篇好文,沿着这篇文章进行了搭建,I ...

  10. 如何在Eclipse下查看JDK源代码

    设置: 1.点 "窗口"-> "首选项" -> "Java" -> "已安装的JRE" 2.此时&qu ...