NodeJs: 使用cluster建立nodejs單機多核叢集(多程序)
阿新 • • 發佈:2019-01-06
前言:
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、程式碼實現
[javascript] view plain copy print?- //開啟叢集服務
- 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) {
- returntypeof 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單機叢集(機器效能壓榨機)
- */