gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区

站長資訊網
最全最豐富的資訊網站

深入解析NodeJS中的進程管理

深入解析NodeJS中的進程管理

熟悉 js 的朋友都知道,js 是單線程的,在 Node 中,采用的是 多進程單線程 的模型。由于javascript單線程的限制,在多核服務器上,我們往往需要啟動多個進程才能最大化服務器性能。

Node.js 進程集群可用于運行多個 Node.js 實例,這些實例可以在其應用程序線程之間分配工作負載。 當不需要進程隔離時,請改用 worker_threads 模塊,它允許在單個 Node.js 實例中運行多個應用程序線程。

零、NodeJS多進程

  • 進程總數,其中一個主進程,cpu 個數 x cpu 核數 個 子進程
  • 無論 child_process 還是 cluster,都不是多線程模型,而是多進程模型
  • 應對單線程問題,通常使用多進程的方式來模擬多線程

一、核心模塊cluster集群

Node 在 V0.8 版本之后引入了 cluster模塊,通過一個主進程 (master) 管理多個子進程 (worker) 的方式實現集群

集群模塊可以輕松創建共享服務器端口的子進程。

cluster 底層是 child_process 模塊,除了可以發送普通消息,還可以發送底層對象 TCPUDP 等, cluster 模塊是 child_process 模塊和 net 模塊的組合應用。 cluster 啟動時,內部會啟動 TCP 服務器,將這個 TCP 服務器端 socket 的文件描述符發給工作進程。

cluster 模塊應用中,一個主進程只能管理一組工作進程,其運作模式沒有 child_process 模塊那么靈活,但是更加穩定:

深入解析NodeJS中的進程管理

1.cluster配置詳情

1.1 引入cluster

const cluster = require('cluster')復

1.2 cluster常用屬性

  • .isMaster 標識主進程, Node<16
  • .isPrimary 標識主進程, Node>16
  • .isWorker 標識子進程
  • .worker 對當前工作進程對象的引用【子進程中】
  • .workers 存儲活動工作進程對象的哈希,以 id 字段為鍵。 這樣可以很容易地遍歷所有工作進程。 它僅在主進程中可用。cluster.wokers[id] === worker【主進程中】
  • .settings 只讀, cluster配置項。在調用 .setupPrimary()或.fork()方法之后,此設置對象將包含設置,包括默認值。之前為空對象。此對象不應手動更改或設置。

cluster.settings配置項詳情:

- `execArgv` <string[]>傳給 Node.js 可執行文件的字符串參數列表。 **默認值:**  `process.execArgv`。 - `exec` <string> 工作進程文件的文件路徑。 **默認值:** `process.argv[1]`。 - `args` <string[]> 傳給工作進程的字符串參數。 **默認值:**`process.argv.slice(2)`。 - `cwd` <string>工作進程的當前工作目錄。 **默認值:**  `undefined` (從父進程繼承)。 - `serialization` <string>指定用于在進程之間發送消息的序列化類型。 可能的值為 `'json'` 和 `'advanced'`。  **默認值:**  `false`。 - `silent` <boolean>是否將輸出發送到父進程的標準輸入輸出。 **默認值:**  `false`。 - `stdio` <Array>配置衍生進程的標準輸入輸出。 由于集群模塊依賴 IPC 來運行,因此此配置必須包含 `'ipc'` 條目。 提供此選項時,它會覆蓋 `silent`。 - `uid` <number>設置進程的用戶標識。  - `gid` <number>設置進程的群組標識。 - `inspectPort` <number> | <Function> 設置工作進程的檢查器端口。 這可以是數字,也可以是不帶參數并返回數字的函數。 默認情況下,每個工作進程都有自己的端口,從主進程的 `process.debugPort` 開始遞增。 - `windowsHide` <boolean> 隱藏通常在 Windows 系統上創建的衍生進程控制臺窗口。 **默認值:**  `false`。

1.3 cluster常用方法

  • .fork([env]) 衍生新的工作進程【主進程中】
  • .setupPrimary([settings]) Node>16
  • .setupMaster([settings]) 用于更改默認的 'fork' 行為,用后設置將出現在 cluster.settings 中。任何設置更改只會影響未來對 .fork()的調用,而不會影響已經運行的工作進程。上述默認值僅適用于第一次調用。Node 小于 16【主進程中】
  • .disconnect([callback]) 當所有工作進程斷開連接并關閉句柄時調用【主進程中】

1.4 cluster常用事件

為了讓集群更加穩定和健壯,cluster 模塊也暴露了許多事件:

  • 'message' 事件, 當集群主進程接收到來自任何工作進程的消息時觸發。
  • 'exit' 事件, 當任何工作進程死亡時,則集群模塊將觸發 'exit' 事件。
cluster.on('exit', (worker, code, signal) => {   console.log('worker %d died (%s). restarting...',               worker.process.pid, signal || code);   cluster.fork(); });
  • 'listening'事件,從工作進程調用 listen() 后,當服務器上觸發 'listening' 事件時,則主進程中的 cluster 也將觸發 'listening' 事件。
cluster.on('listening', (worker, address) => {   console.log(     `A worker is now connected to ${address.address}:${address.port}`); });
  • 'fork' 事件,當新的工作進程被衍生時,則集群模塊將觸發 'fork' 事件。
cluster.on('fork', (worker) => {   timeouts[worker.id] = setTimeout(errorMsg, 2000); });
  • 'setup' 事件,每次調用 .setupPrimary()時觸發。
  • disconnect事件,在工作進程 IPC 通道斷開連接后觸發。 當工作進程正常退出、被殺死、或手動斷開連接時
cluster.on('disconnect', (worker) => {   console.log(`The worker #${worker.id} has disconnected`); });

1.5 Worker類

Worker 對象包含了工作進程的所有公共的信息和方法。 在主進程中,可以使用 cluster.workers 來獲取它。 在工作進程中,可以使用 cluster.worker 來獲取它。

1.5.1 worker常用屬性

  • .id 工作進程標識,每個新的工作進程都被賦予了自己唯一的 id,此 id 存儲在 id。當工作進程存活時,這是在 cluster.workers 中索引它的鍵。
  • .process 所有工作進程都是使用 child_process.fork() 創建,此函數返回的對象存儲為 .process。 在工作進程中,存儲了全局的 process

1.5.2 worker常用方法

  • .send(message[, sendHandle[, options]][, callback]) 向工作進程或主進程發送消息,可選擇使用句柄。在主進程中,這會向特定的工作進程發送消息。 它與 ChildProcess.send()相同。在工作進程中,這會向主進程發送消息。 它與 process.send() 相同。
  • .destroy()
  • .kill([signal])此函數會殺死工作進程。kill() 函數在不等待正常斷開連接的情況下殺死工作進程,它與 worker.process.kill() 具有相同的行為。為了向后兼容,此方法別名為 worker.destroy()
  • .disconnect([callback])發送給工作進程,使其調用自身的 .disconnect()將關閉所有服務器,等待那些服務器上的 'close' 事件,然后斷開 IPC 通道。
  • .isConnect() 如果工作進程通過其 IPC 通道連接到其主進程,則此函數返回 true,否則返回 false。 工作進程在創建后連接到其主進程。
  • .isDead()如果工作進程已終止(由于退出或收到信號),則此函數返回 true。 否則,它返回 false

1.5.3 worker常用事件

為了讓集群更加穩定和健壯,cluster 模塊也暴露了許多事件:

  • 'message' 事件, 在工作進程中。
cluster.workers[id].on('message', messageHandler);
  • 'exit' 事件, 當任何工作進程死亡時,則當前worker工作進程對象將觸發 'exit' 事件。
if (cluster.isPrimary) {   const worker = cluster.fork();   worker.on('exit', (code, signal) => {     if (signal) {       console.log(`worker was killed by signal: ${signal}`);     } else if (code !== 0) {       console.log(`worker exited with error code: ${code}`);     } else {       console.log('worker success!');     }   }); }
  • 'listening'事件,從工作進程調用 listen() ,對當前工作進程進行監聽。
cluster.fork().on('listening', (address) => {   // 工作進程正在監聽 });
  • disconnect事件,在工作進程 IPC 通道斷開連接后觸發。 當工作進程正常退出、被殺死、或手動斷開連接時
cluster.fork().on('disconnect', () => {   //限定于當前worker對象觸發 });

2. 進程通信

Node中主進程和子進程之間通過進程間通信 (IPC) 實現進程間的通信,進程間通過 .send()(a.send表示向a發送)方法發送消息,監聽 message 事件收取信息,這是 cluster模塊 通過集成 EventEmitter 實現的。還是一個簡單的官網的進程間通信例子

  • 子進程:process.on('message')process.send()
  • 父進程:child.on('message')child.send()
# cluster.isMaster # cluster.fork() # cluster.workers # cluster.workers[id].on('message', messageHandler); # cluster.workers[id].send(); # process.on('message', messageHandler);  # process.send();   const cluster = require('cluster'); const http = require('http');  # 主進程 if (cluster.isMaster) {   // Keep track of http requests   console.log(`Primary ${process.pid} is running`);   let numReqs = 0;      // Count requests   function messageHandler(msg) {     if (msg.cmd && msg.cmd === 'notifyRequest') {       numReqs += 1;     }   }    // Start workers and listen for messages containing notifyRequest   // 開啟多進程(cpu核心數)   // 衍生工作進程。   const numCPUs = require('os').cpus().length;   for (let i = 0; i < numCPUs; i++) {     console.log(i)     cluster.fork();   }  // cluster worker 主進程與子進程通信   for (const id in cluster.workers) {     // ***監聽來自子進程的事件     cluster.workers[id].on('message', messageHandler);           // ***向子進程發送     cluster.workers[id].send({                                  type: 'masterToWorker',         from: 'master',         data: {             number: Math.floor(Math.random() * 50)         }     });   }   cluster.on('exit', (worker, code, signal) => {     console.log(`worker ${worker.process.pid} died`);   });  } else {    # 子進程    // 工作進程可以共享任何 TCP 連接   // 在本示例中,其是 HTTP 服務器   // Worker processes have a http server.   http.Server((req, res) => {     res.writeHead(200);     res.end('hello worldn');      //****** !!!!Notify master about the request !!!!!!*******     //****** 向process發送     process.send({ cmd: 'notifyRequest' });           //****** 監聽從process來的     process.on('message', function(message) {          // xxxxxxx     })   }).listen(8000);   console.log(`Worker ${process.pid} started`); }

深入解析NodeJS中的進程管理

2.1 句柄發送與還原

NodeJS 進程之間通信只有消息傳遞,不會真正的傳遞對象。

send() 方法在發送消息前,會將消息組裝成 handle 和 message,這個 message 會經過 JSON.stringify 序列化,也就是說,傳遞句柄的時候,不會將整個對象傳遞過去,在 IPC 通道傳輸的都是字符串,傳輸后通過 JSON.parse 還原成對象。

2.2 監聽共同端口

代碼里有 app.listen(port) 在進行 fork 時,為什么多個進程可以監聽同一個端口呢?

原因是主進程通過 send() 方法向多個子進程發送屬于該主進程的一個服務對象的句柄,所以對于每一個子進程而言,它們在還原句柄之后,得到的服務對象是一樣的,當網絡請求向服務端發起時,進程服務是搶占式的,所以監聽相同端口時不會引起異常。

  • 看下端口被占用的情況:
# master.js  const fork = require('child_process').fork; const cpus = require('os').cpus();  for (let i=0; i<cpus.length; i++) {     const worker = fork('worker.js');     console.log('worker process created, pid: %s ppid: %s', worker.pid, process.pid); }
# worker.js  const http = require('http'); http.createServer((req, res) => { 	res.end('I am worker, pid: ' + process.pid + ', ppid: ' + process.ppid); }).listen(3000);

以上代碼示例,控制臺執行 node master.js 只有一個 worker 可以監聽到 3000 端口,其余將會拋出 Error: listen EADDRINUSE :::3000 錯誤。

  • 那么多進程模式下怎么實現多進程端口監聽呢?答案還是有的,通過句柄傳遞 Node.js v0.5.9 版本之后支持進程間可發送句柄功能
/**  * http://nodejs.cn/api/child_process.html#child_process_subprocess_send_message_sendhandle_options_callback  * message  * sendHandle  */ subprocess.send(message, sendHandle)

當父子進程之間建立 IPC 通道之后,通過子進程對象的 send 方法發送消息,第二個參數 sendHandle 就是句柄,可以是 TCP套接字、TCP服務器、UDP套接字等,為了解決上面多進程端口占用問題,我們將主進程的 socket 傳遞到子進程。

# master.js  const fork = require('child_process').fork; const cpus = require('os').cpus(); const server = require('net').createServer(); server.listen(3000); process.title = 'node-master'  for (let i=0; i<cpus.length; i++) {     const worker = fork('worker.js');          # 句柄傳遞     worker.send('server', server);     console.log('worker process created, pid: %s ppid: %s', worker.pid, process.pid); }
// worker.js let worker; process.title = 'node-worker' process.on('message', function (message, sendHandle) {   if (message === 'server') {     worker = sendHandle;     worker.on('connection', function (socket) {       console.log('I am worker, pid: ' + process.pid + ', ppid: ' + process.ppid)     });   } });

驗證一番,控制臺執行 node master.js

深入解析NodeJS中的進程管理

深入解析NodeJS中的進程管理

深入解析NodeJS中的進程管理

2.3 進程負載均衡

了解 cluster 的話會知道,子進程是通過 cluster.fork() 創建的。在 linux 中,系統原生提供了 fork 方法,那么為什么 Node 選擇自己實現 cluster模塊 ,而不是直接使用系統原生的方法?主要的原因是以下兩點:

  • fork的進程監聽同一端口會導致端口占用錯誤

  • fork的進程之間沒有負載均衡,容易導致驚群現象

cluster模塊 中,針對第一個問題,通過判斷當前進程是否為 master進程,若是,則監聽端口,若不是則表示為 fork 的 worker進程,不監聽端口。

針對第二個問題,cluster模塊 內置了負載均衡功能, master進程 負責監聽端口接收請求,然后通過調度算法(默認為 Round-Robin,可以通過環境變量 NODE_CLUSTER_SCHED_POLICY 修改調度算法)分配給對應的 worker進程

3. 異常捕獲

3.1 未捕獲異常

當代碼拋出了異常沒有被捕獲到時,進程將會退出,此時 Node.js 提供了 process.on('uncaughtException', handler) 接口來捕獲它,但是當一個 Worker 進程遇到未捕獲的異常時,它已經處于一個不確定狀態,此時我們應該讓這個進程優雅退出:

  • 關閉異常 Worker 進程所有的 TCP Server(將已有的連接快速斷開,且不再接收新的連接),斷開和 Master 的 IPC 通道,不再接受新的用戶請求。
  • Master 立刻 fork 一個新的 Worker 進程,保證在線的『工人』總數不變。
  • 異常 Worker 等待一段時間,處理完已經接受的請求后退出。
+---------+                 +---------+ |  Worker |                 |  Master | +---------+                 +----+----+      | uncaughtException         |      +------------+              |      |            |              |                   +---------+      | <----------+              |                   |  Worker |      |                           |                   +----+----+      |        disconnect         |   fork a new worker    |      +-------------------------> + ---------------------> |      |         wait...           |                        |      |          exit             |                        |      +-------------------------> |                        |      |                           |                        |     die                          |                        |                                  |                        |                                  |                        |

3.2 OOM、系統異常

當一個進程出現異常導致 crash 或者 OOM 被系統殺死時,不像未捕獲異常發生時我們還有機會讓進程繼續執行,只能夠讓當前進程直接退出,Master 立刻 fork 一個新的 Worker。


二、子進程

1. child_process模塊

child_process 模塊提供了衍生子進程的能力, 簡單來說就是執行cmd命令的能力。 默認情況下, stdin、 stdout 和 stderr 的管道會在父 Node.js 進程和衍生的子進程之間建立。 這些管道具有有限的(且平臺特定的)容量。 如果子進程寫入 stdout 時超出該限制且沒有捕獲輸出,則子進程會阻塞并等待管道緩沖區接受

贊(0)
分享到: 更多 (0)
?
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区
avav在线看| 日韩精品无码一区二区三区免费| 欧美日韩性生活片| 国产精品日韩三级| 最新中文字幕久久| 日日噜噜夜夜狠狠久久丁香五月| 中文字幕在线观看日| 亚洲 欧美 日韩系列| 亚洲欧美aaa| 成年人网站av| 激情图片qvod| 日韩在线综合网| 国语对白做受xxxxx在线中国 | 亚洲成人动漫在线| 加勒比海盗1在线观看免费国语版| 中文 日韩 欧美| 国产专区在线视频| 波多野结衣家庭教师在线播放| www.中文字幕在线| av在线网址导航| 一级黄色录像免费看| 男人天堂av片| 日韩大片一区二区| 超碰免费在线公开| 阿v天堂2017| 亚洲无在线观看| 欧美亚洲日本一区二区三区| 亚洲黄色小视频在线观看| 亚洲一区二区在线视频观看| 伊人久久在线观看| 一本久道中文无码字幕av| 国产又大又黄又猛| 免费拍拍拍网站| www.日本一区| 欧美日韩性生活片| 一级片黄色免费| 精品人妻一区二区三区四区在线 | 国产又猛又黄的视频| 色哟哟免费网站| 日本xxxx黄色| 成年人视频观看| 久久亚洲a v| 欧美丝袜在线观看| 国产老熟妇精品观看| 亚洲一二区在线观看| 国产熟女高潮视频| 免费一级特黄特色毛片久久看| 奇米视频7777| 成人av一级片| 国产色一区二区三区| 婷婷激情综合五月天| 91最新在线观看| 情侣黄网站免费看| 日本福利视频在线| 国产爆乳无码一区二区麻豆| 亚洲综合伊人久久| 在线观看日本一区二区| 国产乱子夫妻xx黑人xyx真爽| 亚洲免费视频播放| 男插女免费视频| 日本久久高清视频| 五月天六月丁香| 亚洲女人在线观看| 亚洲精品乱码久久久久久动漫| 天天干天天综合| 亚洲天堂网2018| 欧美精品 - 色网| 咪咪色在线视频| 欧美爱爱视频网站| 国产树林野战在线播放| 中文字幕の友人北条麻妃| 一道本在线观看视频| 国产女人18毛片| 国产精品igao激情视频| 九九热只有这里有精品| 免费看国产曰批40分钟| 精品99在线视频| 亚洲国产日韩欧美在线观看| 最新免费av网址| 97av中文字幕| 日本熟妇人妻xxxxx| 91香蕉视频导航| 国产欧美自拍视频| 免费一级特黄毛片| 欧美美女一级片| 久久av高潮av| 久久午夜夜伦鲁鲁一区二区| 国产永久免费网站| 欧美激情亚洲天堂| 97在线播放视频| 欧美国产在线一区| 国产aaa免费视频| 我看黄色一级片| 成人国产一区二区三区| 熟妇人妻无乱码中文字幕真矢织江| 五月天av在线播放| 日本人体一区二区| 亚洲色图欧美自拍| 国产免费黄色av| 992tv快乐视频| 黄色免费网址大全| 欧美日韩福利在线| 亚洲综合激情视频| 国产精品12345| 成年人三级黄色片| 久久久久久久久久久久久国产精品| 成年人三级黄色片| 一本久道综合色婷婷五月| 黑人巨大国产9丨视频| 欧美三级午夜理伦三级富婆| 给我免费播放片在线观看| 激情五月婷婷基地| 黄色国产精品视频| 91国在线高清视频| 97人人模人人爽人人澡| 日韩中文字幕二区| 欧美日韩性生活片| 黄色激情在线视频| 依人在线免费视频| 日韩欧美在线免费观看视频| 欧美 日韩 国产在线观看| 亚洲一区 在线播放| 中文字幕在线观看日| 一区二区三区视频在线观看免费| 成人精品视频在线播放| 亚洲一区 在线播放| 法国空姐在线观看免费| 亚洲男人天堂2021| 国内自拍第二页| 在线播放黄色av| 日韩av影视大全| 久久久精品视频国产| 性鲍视频在线观看| 亚洲男人天堂av在线| 青娱乐精品在线| 日本一区二区免费高清视频| 婷婷中文字幕在线观看| 日本成人性视频| 肉大捧一出免费观看网站在线播放| 一级 黄 色 片一| 无码人妻精品一区二区三区99v| 潘金莲一级淫片aaaaa免费看| 欧美日韩一级在线| 激情成人开心网| 久久久久免费看黄a片app| av动漫在线观看| 亚洲天堂2018av| 亚洲色图都市激情| 乱妇乱女熟妇熟女网站| 国产极品美女高潮无套久久久| 噼里啪啦国语在线观看免费版高清版| 日韩一级片播放| 伊人免费视频二| 黄色一级大片免费| 无码人妻丰满熟妇区毛片| 在线观看免费黄网站| eeuss中文| 成人观看免费完整观看| 性久久久久久久久久久久久久| 欧美大黑帍在线播放| 污污视频网站免费观看| 亚洲欧美日韩不卡| 国产黄色特级片| 国产成人生活片| 日日碰狠狠丁香久燥| 国产奶头好大揉着好爽视频| 欧美日韩在线中文| www.cao超碰| 国产男女免费视频| 天天综合成人网| 国模吧无码一区二区三区| 免费观看黄色的网站| 毛片av免费在线观看| japanese在线播放| 天天爽人人爽夜夜爽| 国产精品久久久久久久乖乖| 中文字幕在线观看日| 3d动漫一区二区三区| 中国一级黄色录像| 日韩一级理论片| 女人和拘做爰正片视频| 麻豆映画在线观看| 性生活免费在线观看| 九九九九免费视频| 日韩精品一区二区在线视频| 波多结衣在线观看| 久草精品在线播放| 精品少妇人妻av免费久久洗澡| 国产精品美女在线播放| 亚洲男人天堂av在线| 蜜桃免费在线视频| 日本爱爱免费视频| 手机看片福利盒子久久| 国产l精品国产亚洲区久久| 久久精品国产sm调教网站演员| 潘金莲一级淫片aaaaaa播放1| 91 视频免费观看| 另类小说第一页| av网站在线不卡| 在线视频日韩一区|