多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

中國最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2

nodejs教程

Node.js 集群

閱讀 (2334)

集群

穩定性: 2 - 不穩定

單個 Node 實例運行在一個線程中。為了更好的利用多核系統的能力,可以啟動 Node 集群來處理負載。

在集群模塊里很容易就能創建一個共享所有服務器接口的進程。

var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  // Fork workers.
  for (var i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', function(worker, code, signal) {
    console.log('worker ' + worker.process.pid + ' died');
  });
} else {
  // Workers can share any TCP connection
  // In this case its a HTTP server
  http.createServer(function(req, res) {
    res.writeHead(200);
    res.end("hello world\n");
  }).listen(8000);
}

運行 Node 后,將會在所有工作進程里共享 8000 端口。

% NODE_DEBUG=cluster node server.js
23521,Master Worker 23524 online
23521,Master Worker 23526 online
23521,Master Worker 23523 online
23521,Master Worker 23528 online

這個特性是最近才引入的,大家可以試試并提供反饋。

還要注意,在 Windows 系統里還不能在工作進程中創建一個被命名的管道服務器。

如何工作

child_process.fork 方法派生工作進程,所以它能通過 IPC 和父進程通訊,并相互傳遞句柄。

集群模塊通過2種分發模式來處理連接。

第一種(默認方法,除了 Windows 平臺)為循環式。主進程監聽一個端口,接收新的連接,再輪流的分發給工作進程。

第二種,主進程監聽 socket,并發送給感興趣的工作進程,工作進程直接接收連接。

第二種方法理論上性能最高。實際上,由于操作系統各式各樣,分配往往分配不均。列如,70%的連接終止于2個進程,實際上共有8個進程。

因為 server.listen() 將大部分工作交給了主進程,所以一個普通的 Node.js 進程和一個集群工作進程會在三種情況下有所區別:

  1. server.listen({fd: 7}) 由于消息被傳回主進程,所以將會監聽主進程里的文件描述符,而不是其他工作進程里的文件描述符 7。
  2. server.listen(handle) 監聽一個明確地句柄,會使得工作進程使用指定句柄,而不是與主進程通訊。如果工作進程已經擁有了該句柄,前提是您知道在做什么。
  3. server.listen(0) 通常它會讓服務器隨機監聽端口。然而在集群里每個工作進程 listen(0) 時會收到相同的端口。實際上僅第一次是隨機的,之后是可預測的。如果你想監聽一個特定的端口,可以根據集群的工作進程的ID生產一個端口ID 。

在 Node.js 或你的程序里沒有路由邏輯,工作進程見也沒有共享狀態。因此,像登錄和會話這樣的工作,不要設計成過度依賴內存里的對象。

因為工作線程都是獨立的,你可以根據需求來殺死或者派生而不會影響其他進程。只要仍然有工作進程,服務器還會接收連接。Node 不會自動管理工作進程的數量,這是你的責任,你可以根據自己需求來管理。

cluster.schedulingPolicy

調度策略 cluster.SCHED_RR 表示輪流制,cluster.SCHED_NONE 表示操作系統處理。這是全局性的設定,一旦你通過 cluster.setupMaster() 派生了第一個工作進程,它就不可更改了。

SCHED_RR 是除 Windows 外所有系統的默認設置。只要 libuv 能夠有效地分配 IOCP 句柄并且不產生巨大的性能損失,Windows 也會改為 SCHED_RR 方式。

cluster.schedulingPolicy 也可通過環境變量 NODE_CLUSTER_SCHED_POLICY 來更改。有效值為 "rr""none"

cluster.settings

  • {Object}
    • execArgv {Array} 傳給可執行的 Node 的參數列表(默認=process.execArgv)
    • exec {String} 執行文件的路徑。 (默認=process.argv[1])
    • args {Array} 傳給工作進程的參數列表(默認=process.argv.slice(2))
    • silent {Boolean}是否將輸出發送給父進程的 stdio。(默認=false)
    • uid {Number} 設置用戶進程的ID。 (See setuid(2)。)
    • gid {Number} 設置進程組的ID。 (See setgid(2)。)

調用 .setupMaster() (或 .fork()) 方法后,這個 settings 對象會包含設置內容,包括默認值。

設置后會立即凍結,因為.setupMaster()只能調用一次。

這個對象不應該被手動改變或設置。

cluster.isMaster

  • {Boolean}

如果是主進程,返回 true。如果 process.env.NODE_UNIQUE_ID 未定義,isMastertrue

cluster.isWorker

  • {Boolean}

如果不是主進程返回 true (和 cluster.isMaster 相反)。

事件: 'fork'

  • worker {Worker object}

當一個新的工作進程被分支出來,集群模塊會產生 'fork' 事件。它可用于記錄工作進程,并創建自己的超時管理。

var timeouts = [];
function errorMsg() {
  console.error("Something must be wrong with the connection ...");
}

cluster.on('fork', function(worker) {
  timeouts[worker.id] = setTimeout(errorMsg, 2000);
});
cluster.on('listening', function(worker, address) {
  clearTimeout(timeouts[worker.id]);
});
cluster.on('exit', function(worker, code, signal) {
  clearTimeout(timeouts[worker.id]);
  errorMsg();
});

事件: 'online'

  • worker {Worker object}

分支出一個新的工作進程后,它會響應在線消息。當主線程接收到在線消息后,它會觸發這個事件。'fork' 和 'online' 之間的區別在于,主進程分支一個工作進程后會調用 fork,而工作進程運行后會調用 emitted。

cluster.on('online', function(worker) {
  console.log("Yay, the worker responded after it was forked");
});

事件: 'listening'

  • worker {Worker object}
  • address {Object}

工作進程調用 listen() 時,服務器會觸發'listening'事件,同時也會在主進程的集群里觸發。

事件處理函數有兩個參數,worker 包含工作進程對象,address 包含以下屬性:address, portaddressType。如果工作進程監聽多個地址的時候,這些東西非常有用。

cluster.on('listening', function(worker, address) {
  console.log("A worker is now connected to " + address.address + ":" + address.port);
});

addressType 是以下內容:

  • 4 (TCPv4)
  • 6 (TCPv6)
  • -1 (unix domain socket)
  • "udp4" or "udp6" (UDP v4 or v6)*

事件: 'disconnect'

  • worker {Worker object}

當一個工作進程的 IPC 通道關閉時會觸發這個事件。當工作進程正常退出,被殺死,或者手工關閉(例如worker.disconnect())時會調用。

disconnectexit 事件間可能存在延遲。 這些事件可以用來檢測進程是否卡在清理過程中,或者存在長連接。

cluster.on('disconnect', function(worker) {
  console.log('The worker #' + worker.id + ' has disconnected');
});

事件: 'exit'

  • worker {Worker object}
  • code {Number} 如果正常退出,則為退出代碼.
  • signal {String} 使得進程被殺死的信號名 (比如. 'SIGHUP')

當任意一個工作進程終止的時候,集群模塊會觸發 'exit' 事件。

可以調用 .fork() 重新啟動工作進程。

cluster.on('exit', function(worker, code, signal) {
  console.log('worker %d died (%s). restarting...',
    worker.process.pid, signal || code);
  cluster.fork();
});

參見 child_process event: 'exit'.

事件: 'setup'

  • settings {Object}

調用.setupMaster() 后會被觸發。

settings 對象就是 cluster.settings 對象。

詳細內容參見 cluster.settings

cluster.setupMaster([settings])

  • settings {Object}
    • exec {String} 執行文件的路徑。 (默認=process.argv[1])
    • args {Array}傳給工作進程的參數列表(默認=process.argv.slice(2))
    • silent {Boolean} 是否將輸出發送給父進程的 stdio.

setupMaster用來改變默認的 'fork' 。 一旦調用,settings值將會出現在cluster.settings里。

注意:

  • 改變任何設置,僅會對未來的工作進程產生影響,不會影響對目前已經運行的進程
  • 工作進程里,僅能改變傳遞給 .fork()env 屬性。
  • 以上的默認值,僅在第一次調用的時候有效,之后的默認值是調用 cluster.setupMaster() 后的值。

例如:

var cluster = require('cluster');
cluster.setupMaster({
  exec: 'worker.js',
  args: ['--use', 'https'],
  silent: true
});
cluster.fork(); // https worker
cluster.setupMaster({
  args: ['--use', 'http']
});
cluster.fork(); // http worker

僅能在主進程里調用。

cluster.fork([env])

  • env {Object} 添加到子進程環境變量中的鍵值。
  • return {Worker object}

派生一個新的工作進程。

僅能在主進程里調用。

cluster.disconnect([callback])

  • callback {Function} 當所有工作進程都斷開連接,并且關閉句柄后被調用。

cluster.workers 里的每個工作進程可調用 .disconnect() 關閉。

關閉所有的內部句柄連接,并且沒有任何等待處理的事件時,允許主進程優雅的退出。

這個方法有一個可選參數,會在完成時被調用。

僅能在主進程里調用。

cluster.worker

  • {Object}

對當前工作進程對象的引用。主進程中不可用。

var cluster = require('cluster');

if (cluster.isMaster) {
  console.log('I am master');
  cluster.fork();
  cluster.fork();
} else if (cluster.isWorker) {
  console.log('I am worker #' + cluster.worker.id);
}

cluster.workers

  • {Object}

存儲活躍工作對象的哈希表,主鍵是 id,能方便的遍歷所有工作進程,僅在主進程可用。

當工作進程關閉連接并退出后,將會從 cluster.workers 里移除。這兩個事件的次序無法確定,僅能保證從cluster.workers 移除會發生在 'disconnect''exit' 之后。

// Go through all workers
function eachWorker(callback) {
  for (var id in cluster.workers) {
    callback(cluster.workers[id]);
  }
}
eachWorker(function(worker) {
  worker.send('big announcement to all workers');
});

如果希望通過通訊通道引用工作進程,那么使用工作進程的 id 來查詢最簡單。

socket.on('data', function(id) {
  var worker = cluster.workers[id];
});

Class: Worker

一個 Worker 對象包含工作進程所有公開的信息和方法。在主進程里可用通過 cluster.workers 來獲取,在工作進程里可以通過 cluster.worker 來獲取。

worker.id

  • {String}

每一個新的工作進程都有獨立的唯一標示,它就是 id

當工作進程可用時,id 就是 cluster.workers 里的主鍵。

worker.process

  • {ChildProcess object}

所有工作進程都是通用 child_process.fork() 創建的,該函數返回的對象被儲存在 process 中。

參見: Child Process module

注意,當 process.suicide 不是 true 的時候,會觸發 'disconnect' 事件,并使得工作進程調用 process.exit(0) 。它會保護意外的連接關閉。

worker.suicide

  • {Boolean}

調用 .kill().disconnect() 后設置,在這之前是 undefined

worker.suicide 能讓你區分出是自愿的還是意外退出,主進程可以根據這個值,來決定是否是重新派生成工作進程。

cluster.on('exit', function(worker, code, signal) {
  if (worker.suicide === true) {
    console.log('Oh, it was just suicide\' – no need to worry').
  }
});

// kill worker
worker.kill();

worker.send(message[, sendHandle])

  • message {Object}
  • sendHandle {Handle object}

這個函數和 child_process.fork() 提供的 send 方法相同。主進程里你必須使用這個函數給指定工作進程發消息。

在工作進程里,你也可以用 process.send(message)

這個例子會回應所有來自主進程的消息:

if (cluster.isMaster) {
  var worker = cluster.fork();
  worker.send('hi there');

} else if (cluster.isWorker) {
  process.on('message', function(msg) {
    process.send(msg);
  });
}

worker.kill([signal='SIGTERM'])

  • signal {String}發送給工作進程的殺死信號的名稱

這個函數會殺死工作進程。在主進程里,它會關閉 worker.process,一旦關閉會發送殺死信號。在工作進程里,關閉通道,退出,返回代碼0

會導致 .suicide 被設置。

為了保持兼容性,這個方法的別名是worker.destroy()

注意,在工作進程里有process.kill(),于此不同。

worker.disconnect()

在工作進程里,這個函數會關閉所有服務器,等待 'close' 事件,關閉 IPC 通道。

在主進程里,發給工作進程一個內部消息,用來調用.disconnect()

會導致 .suicide 被設置。

注意,服務器關閉后,不再接受新的連接,但可以接受新的監聽。已經存在的連接允許正常退出。當連接為空得時候,工作進程的 IPC 通道運行優雅的退出。

以上僅能適用于服務器的連接,客戶端的連接由工作進程關閉。

注意,在工作進程里,存在 process.disconnect,但并不是這個函數,它是 disconnect。

由于長連接可能會阻塞進程關閉連接,有一個較好的辦法是發消息給應用,這樣應用會想辦法關閉它們。超時管理也是不錯,如果超過一定時間后還沒有觸發 disconnect 事件,將會殺死進程。

if (cluster.isMaster) {
  var worker = cluster.fork();
  var timeout;

  worker.on('listening', function(address) {
    worker.send('shutdown');
    worker.disconnect();
    timeout = setTimeout(function() {
      worker.kill();
    }, 2000);
  });

  worker.on('disconnect', function() {
    clearTimeout(timeout);
  });

} else if (cluster.isWorker) {
  var net = require('net');
  var server = net.createServer(function(socket) {
    // connections never end
  });

  server.listen(8000);

  process.on('message', function(msg) {
    if(msg === 'shutdown') {
      // initiate graceful close of any connections to server
    }
  });
}

worker.isDead()

工作進程結束,返回 true, 否則返回 false

worker.isConnected()

當工作進程通過 IPC 通道連接主進程時,返回 true ,否則 false 。工作進程創建后會連接到主進程。當disconnect事件觸發后會關閉連接。

事件: 'message'

  • message {Object}

該事件和 child_process.fork() 所提供的一樣。在主進程中您應當使用該事件,而在工作進程中您也可以使用 process.on('message')

例如,有一個集群使用消息系統在主進程中統計請求的數量:

var cluster = require('cluster');
var http = require('http');

if (cluster.isMaster) {

  // Keep track of http requests
  var numReqs = 0;
  setInterval(function() {
    console.log("numReqs =", numReqs);
  }, 1000);

  // Count requestes
  function messageHandler(msg) {
    if (msg.cmd && msg.cmd == 'notifyRequest') {
      numReqs += 1;
    }
  }

  // Start workers and listen for messages containing notifyRequest
  var numCPUs = require('os').cpus().length;
  for (var i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  Object.keys(cluster.workers).forEach(function(id) {
    cluster.workers[id].on('message', messageHandler);
  });

} else {

  // Worker processes have a http server.
  http.Server(function(req, res) {
    res.writeHead(200);
    res.end("hello world\n");

    // notify master about the request
    process.send({ cmd: 'notifyRequest' });
  }).listen(8000);
}

事件: 'online'

cluster.on('online') 事件類似, 僅能在特定工作進程里觸發。

cluster.fork().on('online', function() {
  // Worker is online
});

不會在工作進程里觸發。

事件: 'listening'

  • address {Object}

cluster.on('listening') 事件類似, 僅能在特定工作進程里觸發。

cluster.fork().on('listening', function(address) {
  // Worker is listening
});

不會在工作進程里觸發。

事件: 'disconnect'

cluster.on('disconnect') 事件類似, 僅能在特定工作進程里觸發。

cluster.fork().on('disconnect', function() {
  // Worker has disconnected
});

事件: 'exit'

  • code {Number} 正常退出時的退出代碼.
  • signal {String} 使得進程被終止的信號的名稱(比如 SIGHUP)。

cluster.on('exit') 事件類似, 僅能在特定工作進程里觸發。

var worker = cluster.fork();
worker.on('exit', function(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!");
  }
});

事件: 'error'

child_process.fork()事件類似。

工作進程里,你也可以用 process.on('error')

關閉
程序員人生
主站蜘蛛池模板: 日韩尤物在线 | 女人18毛片a | 精品国产一区二区三区香蕉沈先生 | 午夜亚洲国产理论秋霞 | 欧美性bbbbxxxxx| 黄色综合 | 亚洲成人福利 | 手机在线视频观看 | 欧美黄色片一级 | 国产精品高清一区二区三区不卡 | 久久精品国产精品亚洲综合 | 日韩中文字幕一区二区不卡 | 国产人成精品午夜在线观看 | 欧美一级aa天码毛片 | 国产亚洲精品久久久久久无 | 欧美国产免费 | 色午夜视频 | 国产91精品高清一区二区三区 | 欧美国产成人精品一区二区三区 | 精彩视频在线观看 | 图片区 日韩 欧美 亚洲 | 在线不卡国产 | 欧美超清性videosfree | 国产成人综合久久 | 污污成人一区二区三区四区 | 国产成人精品免费视频大 | 婷婷综合缴情亚洲五月伊 | 成人精品一区二区三区 | 狠狠色噜噜狠狠狠狠五月婷 | 亚洲国产日韩欧美综合久久 | 精品国产成人三级在线观看 | 激情粉嫩精品国产尤物 | 午夜噜噜| 美国一级特级毛片片aa视频 | 色网站在线 | 欧美一级淫片aaaaaaa视频 | 吃奶跟添下面特舒服 | 最近中文字幕在线视频 | 国产一区二区三区福利 | 欧美日韩一二三四区 | 欧美日本一区二区三区道 |