国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 語言 > JavaScript > 正文

詳解通過源碼解析Node.js中cluster模塊的主要功能實現

2024-05-06 15:34:11
字體:
來源:轉載
供稿:網友

眾所周知,Node.js中的JavaScript代碼執行在單線程中,非常脆弱,一旦出現了未捕獲的異常,那么整個應用就會崩潰。這在許多場景下,尤其是web應用中,是無法忍受的。通常的解決方案,便是使用Node.js中自帶的cluster模塊,以master-worker模式啟動多個應用實例。然而大家在享受cluster模塊帶來的福祉的同時,不少人也開始好奇:

    為什么我的應用代碼中明明有app.listen(port);,但cluter模塊在多次fork這份代碼時,卻沒有報端口已被占用? Master是如何將接收的請求傳遞至worker中進行處理然后響應的?

讓我們從Node.js項目的lib/cluster.js中的代碼里,來一勘究竟。

問題一

為了得到這個問題的解答,我們先從worker進程的初始化看起,master進程在fork工作進程時,會為其附上環境變量NODE_UNIQUE_ID,是一個從零開始的遞增數:

// lib/cluster.js// ...function createWorkerProcess(id, env) { // ... workerEnv.NODE_UNIQUE_ID = '' + id; // ... return fork(cluster.settings.exec, cluster.settings.args, {  env: workerEnv,  silent: cluster.settings.silent,  execArgv: execArgv,  gid: cluster.settings.gid,  uid: cluster.settings.uid });}

隨后Node.js在初始化時,會根據該環境變量,來判斷該進程是否為cluster模塊fork出的工作進程,若是,則執行workerInit()函數來初始化環境,否則執行masterInit()函數。

在workerInit()函數中,定義了cluster._getServer方法,這個方法在任何net.Server實例的listen方法中,會被調用:

// lib/net.js// ...function listen(self, address, port, addressType, backlog, fd, exclusive) { exclusive = !!exclusive; if (!cluster) cluster = require('cluster'); if (cluster.isMaster || exclusive) {  self._listen2(address, port, addressType, backlog, fd);  return; } cluster._getServer(self, {  address: address,  port: port,  addressType: addressType,  fd: fd,  flags: 0 }, cb); function cb(err, handle) {  // ...  self._handle = handle;  self._listen2(address, port, addressType, backlog, fd); }}

你可能已經猜到,問題一的答案,就在這個cluster._getServer函數的代碼中。它主要干了兩件事:

    向master進程注冊該worker,若master進程是第一次接收到監聽此端口/描述符下的worker,則起一個內部TCP服務器,來承擔監聽該端口/描述符的職責,隨后在master中記錄下該worker。 Hack掉worker進程中的net.Server實例的listen方法里監聽端口/描述符的部分,使其不再承擔該職責。

對于第一件事,由于master在接收,傳遞請求給worker時,會符合一定的負載均衡規則(在非Windows平臺下默認為輪詢),這些邏輯被封裝在RoundRobinHandle類中。故,初始化內部TCP服務器等操作也在此處:

// lib/cluster.js// ...function RoundRobinHandle(key, address, port, addressType, backlog, fd) { // ... this.handles = []; this.handle = null; this.server = net.createServer(assert.fail); if (fd >= 0)  this.server.listen({ fd: fd }); else if (port >= 0)  this.server.listen(port, address); else  this.server.listen(address); // UNIX socket path. /// ...}            
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

主站蜘蛛池模板: 和平区| 原阳县| 邻水| 施甸县| 临江市| 芷江| 安义县| 香河县| 桐城市| 林西县| 承德县| 镇平县| 禹城市| 扎鲁特旗| 唐山市| 财经| 黄龙县| 孝昌县| 庆云县| 茂名市| 电白县| 保德县| 鲁山县| 康马县| 临潭县| 宁波市| 福鼎市| 桓台县| 安西县| 襄垣县| 中宁县| 元江| 博乐市| 鹤庆县| 阳信县| 邮箱| 南平市| 鱼台县| 永平县| 仁布县| 开江县|