日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

集群资源分配_分析下 Node.js 关于集群的那些事

發布時間:2024/4/14 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 集群资源分配_分析下 Node.js 关于集群的那些事 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

需要了解的基礎概念 一個應用程序中,至少包含一個進程,一個進程至少包含一個線程。

  • 進程(Process)是計算機中的程序關于某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位
  • 線程(Thread)是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。

Node 的特點:

  • 主線程是單進程(后面版本出現了線程概念,開銷較大);
  • 基于事件驅動,異步非阻塞 I/O;
  • 可用于高并發場景。

nodejs 原有版本中沒有實現多線程,為了充分利用多核 cpu,可以使用子進程實現內核的負載均衡。

node 需要解決的問題:

  • node 做耗時的計算時候,造成阻塞。
  • node 如何開啟子進程
  • 開發過程中如何實現進程守護

概念太多,我們從具體案例入手,看看單線程到底會帶來什么問題。

單線程的缺點

//?file:?question.jsconst?http?=?require('http');http.createServer((req,?res)?=>?{??if?(req.url?===?'/sum')?{?//?求和????var?endTime?=?new?Date().getTime()?+?10000????while?(new?Date().getTime()?

操作步驟

  • node question.js
  • 打開瀏覽器,在一個 tab1 上訪問 /sum 。快速打開另一個 tab2,訪問 / 。

請問會出現什么現象? 我們發現 tab1 在轉圈, tab2 也在轉圈,這個現象就很奇怪了。tab1 在轉圈我們可以理解,因為我們需要花費是 10s,但是 tab2 也需要 10s 后,才能被訪問。這就很奇怪了。

這個問題就相當于,別人訪問這個瀏覽器阻塞了 10s,你也要跟著阻塞 10s。這個問題就很難被接受了。因此得出結論,node 不太適合做 cpu 密集型的服務。

如何解決這個問題?

為了解決這個問題,我們引入子進程。

file:?calc.jsvar?endTime?=?new?Date().getTime()?+?10000while?(new?Date().getTime()?

改造 question.js

file:?question.jsconst?http?=?require('http');const?{fork}?=?require('child_process');const?path?=?require('path');http.createServer((req,?res)?=>?{??if?(req.url?===?'/sum')?{?//?求和??????//?var?endTime?=?new?Date().getTime()?+?10000??????//?while?(new?Date().getTime()?

重新啟動 node question.js,發現 tab2,就不會阻塞了。

總結:node 作為服務器的話,需要開啟子進程來解決 cpu 密集型的操作。以防止主線程被阻塞

子進程的使用 (child_process)

使用的方法

  • spawn 異步生成子進程
  • fork 產生一個新的 Node.js 進程,并使用建立的 IPC 通信通道調用指定的模塊,該通道允許在父級和子級之間發送消息。
  • exec 產生一個 shell 并在該 shell 中運行命令
  • execFile 無需產生 shell

spawn

spawn 產卵,可以通過此方法創建一個子進程

let?{?spawn?}?=?require("child_process");let?path?=?require("path");//?通過node命令執行sub_process.js文件let?childProcess?=?spawn("node",['sub_process.js'],?{??cwd:?path.resolve(__dirname,?"test"),?//?找文件的目錄是test目錄下??stdio:?[0,?1,?2]});//?監控錯誤childProcess.on("error",?function(err)?{??console.log(err);});//?監聽關閉事件childProcess.on("close",?function()?{??console.log("close");});//?監聽退出事件childProcess.on("exit",?function()?{??console.log("exit");});

stdio 這個屬性非常有特色,這里我們給了 0,1,2 那么分別代表什么呢? stdio

  • 0,1,2 分別對應當前主進程的 process.stdin,process.stdout,process.stderr,意味著主進程和子進程共享標準輸入和輸出
  • let?childProcess?=?spawn("node",['sub_process.js'],?{??cwd:?path.resolve(__dirname,?"test"),?//?找文件的目錄是test目錄下??stdio:?[0,?1,?2]});

    可以在當前進程下打印 sub_process.js 執行結果

  • 默認不提供 stdio 參數時,默認值為 stdio:['pipe'],也就是只能通過流的方式實現進程之間的通信
  • let?{?spawn?}?=?require("child_process");let?path?=?require("path");//?通過node命令執行sub_process.js文件let?childProcess?=?spawn("node",['sub_process.js'],?{??cwd:?path.resolve(__dirname,?"test"),??stdio:['pipe']?//?通過流的方式});//?子進程讀取寫入的數據childProcess.stdout.on('data',function(data){????console.log(data);});//?子進程像標準輸出中寫入process.stdout.write('hello');
  • 使用 ipc 方式通信,設置值為 stdio:['pipe','pipe','pipe','ipc'],可以通過 on('message')和 send 方法進行通信
  • ??let?{?spawn?}?=?require("child_process");??let?path?=?require("path");??//?通過node命令執行sub_process.js文件??let?childProcess?=?spawn("node",['sub_process.js'],?{????cwd:?path.resolve(__dirname,?"test"),????stdio:['pipe','pipe','pipe','ipc']?//?通過流的方式??});??//?監聽消息??childProcess.on('message',function(data){??????console.log(data);??});??//?發送消息??process.send('hello');
  • 還可以傳入ignore 進行忽略 , 傳入inherit表示默認共享父進程的標準輸入和輸出
  • 產生獨立進程

    let?{?spawn?}?=?require("child_process");let?path?=?require("path");//?通過node命令執行sub_process.js文件let?child?=?spawn('node',['sub_process.js'],{????cwd:path.resolve(__dirname,'test'),????stdio:?'ignore',????detached:true?//?獨立的線程});child.unref();?//?放棄控制

    作用:開啟線程后,并且放棄對線程的控制。我們就可以不占用控制臺后臺運行了。

    fork

    衍生新的進程,默認就可以通過ipc方式進行通信

    let?{?fork?}?=?require("child_process");let?path?=?require("path");//?通過node命令執行sub_process.js文件let?childProcess?=?fork('sub_process.js',?{??cwd:?path.resolve(__dirname,?"test"),});childProcess.on('message',function(data){????console.log(data);});

    fork是基于spawn的,可以多傳入一個silent屬性, 設置是否共享輸入和輸出

    fork原理

    function?fork(filename,options){????let?stdio?=?['inherit','inherit','inherit']????if(options.silent){?//?如果是安靜的??就忽略子進程的輸入和輸出????????stdio?=?['ignore','ignore','ignore']????}????stdio.push('ipc');?//?默認支持ipc的方式????options.stdio?=?stdio????return?spawn('node',[filename],options)}

    execFile

    通過node命令,直接執行某個文件

    let?childProcess?=?execFile("node",['./test/sub_process'],function(err,stdout,stdin){????console.log(stdout);?});

    內部調用的是spawn方法

    exec

    let?childProcess?=?exec("node?'./test/sub_process'",function(err,stdout,stdin){????console.log(stdout)});

    內部調用的是execFile,其實以上的三個方法都是基于spawn的

    實現集群

    //?file?cluster.js?主線程//?內部原理就是多進程?//?分布式??前端和后端??集群?多個功能相同的來分擔工作//?集群?就可以實現多個cpu的負載均衡?一般情況?//?不同進程?監聽同一個端口號const?{fork}??=?require('child_process');const?cpus?=?require('os').cpus().length;const?path?=?require('path');//?現在主進程中先啟動一個服務const?http?=?require('http');let?server?=?http.createServer(function?(req,res)?{????res.end(process.pid+'?'+?'?main?end')}).listen(3000);for(let?i?=?0?;?i?//?file??worker/server.js?子進程const?http?=?require('http');process.on('message',function?(data,server)?{????http.createServer(function?(req,res)?{????????????????res.end(process.pid+'?'+?'end')????}).listen(server);?//?多進程監控同一個端口號?})//?file?http.get.js?請求腳本const?http?=?require('http');for(let?i?=0?;?i?

    啟動請求腳本以后,多次發送請,可以清楚的發現請求的進程pid 不是同一個pid。

    cluster模塊實現集群

    let?cluster?=?require("cluster");let?http?=?require("http");let?cpus?=?require("os").cpus().length;const?workers?=?{};if?(cluster.isMaster)?{????cluster.on('exit',function(worker){????????console.log(worker.process.pid,'death')????????let?w?=?cluster.fork();????????workers[w.pid]?=?w;????})??for?(let?i?=?0;?i??{??????res.end(process.pid+'','pid');????})????.listen(3000);??console.log("server?start",process.pid);}

    上述的代碼有點反人類,但是 c++ 中也是存在這樣操作進程的。

    另一種方式

    //?file??const?cluster?=?require('cluster');const?cpus?=?require('os').cpus();//?入口文件cluster.setupMaster({????exec:?require('path').resolve(__dirname,'worker/cluster.js'),});cluster.on('exit',function?(worker)?{????console.log(worker.process.pid);????cluster.fork();?//?在開啟個進程})for(let?i?=?0;?i?//?node?worker/cluster.js?//?我們的項目邏輯很多???const?http?=?require('http');??http.createServer((req,?res)?=>?{????if?(Math.random()?>?0.5)?{??????SDSADADSSA();????}????//?在集群的環境下可以監聽同一個端口號????res.end(process.pid?+?':'?+?'end')??}).listen(3000);

    pm2應用

    pm2可以把你的應用部署到服務器所有的CPU上,實現了多進程管理、監控、及負載均衡

    安裝pm2

    npm?install?pm2?-g?#?安裝pm2pm2?start?server.js?--watch?-i?max?#?啟動進程pm2?list?#?顯示進程狀態pm2?kill?#?殺死全部進程pm2?start?npm?--?run?dev?#?啟動npm腳本

    pm2配置文件

    pm2?ecosystem

    配置項目自動部署

    module.exports?=?{??apps?:?[{????name:?'my-project',????script:?'server.js',????//?Options?reference:?https://pm2.io/doc/en/runtime/reference/ecosystem-file/????args:?'one?two',????instances:?2,????autorestart:?true,????watch:?false,????max_memory_restart:?'1G',????env:?{??????NODE_ENV:?'development'????},????env_production:?{??????NODE_ENV:?'production'????}??}],??deploy?:?{????production?:?{??????user?:?'root',??????host?:?'39.106.14.146',??????ref??:?'origin/master',??????repo?:?'https://github.com/wakeupmypig/pm2-deploy.git',??????path?:?'/home',??????'post-deploy'?:?'npm?install?&&?pm2?reload?ecosystem.config.js?--env?production'????}??}};pm2?deploy?ecosystem.config.js?production?setup?#?執行git?clonepm2?deploy?ecosystem.config.js?production?#?啟動pm2

    總結

    以上是生活随笔為你收集整理的集群资源分配_分析下 Node.js 关于集群的那些事的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。