2011-12-16 21 views
19

Tôi đã làm việc (chứng khoán) kịch bản từ nodeNodeJS | Cụm: Làm thế nào để gửi dữ liệu từ chủ tới tất cả hoặc một đứa trẻ/công nhân?

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

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

    worker.on('message', function(msg) { 
     if (msg.cmd && msg.cmd == 'notifyRequest') { 
     numReqs++; 
     } 
    }); 
    } 

    setInterval(function() { 
    console.log("numReqs =", numReqs); 
    }, 1000); 
} else { 
    // Worker processes have a http server. 
    http.Server(function(req, res) { 
    res.writeHead(200); 
    res.end("hello world\n"); 
    // Send message to master process 
    process.send({ cmd: 'notifyRequest' }); 
    }).listen(8000); 
} 

Trong kịch bản trên, chúng tôi có thể gửi dữ liệu từ người lao động đến quá trình tổng thể một cách dễ dàng. Nhưng làm cách nào để gửi dữ liệu từ chủ tới nhân viên/công nhân? Với các ví dụ, nếu có thể.

Trả lời

1

Bạn sẽ có thể gửi một tin nhắn từ tổng thể để người lao động như thế này:

worker.send({message:'hello'}) 

vì "cluster.fork được thực hiện trên đầu trang của child_process.fork" (cluster.fork được thực hiện trên đầu trang của child_process.fork)

+0

Có nó hoạt động, cảm ơn bạn! Nói cách khác: trong khi forking công nhân tôi nên lưu trữ chúng trong một mảng. Và lặp lại mảng này để gửi dữ liệu đến mọi trẻ em. Là bất kỳ cách nào khác để gửi dữ liệu cho tất cả các công nhân mà không lưu trữ và lặp lại. – htonus

+0

Nếu bạn không muốn lưu trữ các công nhân vào một mảng và lặp qua chúng để gửi tin nhắn, bạn có thể sử dụng một ổ cắm miền unix để truyền đạt thông điệp từ tổng thể đến các nhân viên. – alessioalex

+0

Tôi cho rằng bạn có thể tạo một EventEmitter trong master, chúng phát ra một sự kiện bất cứ khi nào nhận được một tin nhắn. Sau khi tạo mỗi công nhân, bạn chỉ cần thêm một trình lắng nghe vào EventEmitter để gửi thông báo tới người lao động. Tất nhiên điều này vẫn còn thực hiện lưu trữ các tài liệu tham khảo của người nghe (do đó của người lao động quá) vào EventEmitter, nhưng hey, ít nhất bạn không cần phải nhìn vào nó – cheng81

36

Vì cluster.fork được triển khai ở trên cùng của child_process.fork, bạn có thể gửi tin nhắn từ tổng thể đến người lao động bằng cách sử dụng worker.send({ msg: 'test' }) và từ công nhân đến chủ nhân theo số process.send({ msg: 'test' });. Bạn nhận được các tin nhắn như vậy: worker.on('message', callback) (từ công nhân đến chủ) và process.on('message', callback); (từ chủ nhân đến công nhân).

Dưới đây là ví dụ đầy đủ của tôi, bạn có thể kiểm tra nó bằng cách duyệt http://localhost:8000/ Sau đó, người lao động sẽ gửi một thông điệp tới các bậc thầy và các bậc thầy sẽ trả lời:

var cluster = require('cluster'); 
var http = require('http'); 
var numReqs = 0; 
var worker; 

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

    worker.on('message', function(msg) { 
     // we only want to intercept messages that have a chat property 
     if (msg.chat) { 
     console.log('Worker to master: ', msg.chat); 
     worker.send({ chat: 'Ok worker, Master got the message! Over and out!' }); 
     } 
    }); 

    } 
} else { 
    process.on('message', function(msg) { 
    // we only want to intercept messages that have a chat property 
    if (msg.chat) { 
     console.log('Master to worker: ', msg.chat); 
    } 
    }); 
    // Worker processes have a http server. 
    http.Server(function(req, res) { 
    res.writeHead(200); 
    res.end("hello world\n"); 
    // Send message to master process 
    process.send({ chat: 'Hey master, I got a new request!' }); 
    }).listen(8000); 
} 
+0

Thực ra tôi muốn tạo ra máy chủ push cho (web/flash) socket clients. Phiên bản hiện tại ngăn xếp trên 1000 kết nối đồng thời. Vì vậy, tôi quyết định tạo ra một số công nhân với người nghe socket.io. Điều này có nghĩa là tôi cần truyền dữ liệu cho người lao động theo cách không đồng bộ. – htonus

+2

Điều đó nghe có vẻ ổn, đảm bảo bạn sử dụng Socket.IO với RedisStore. – alessioalex

+1

Điều này sẽ không hoạt động. 'var' bên trong' for'? 'worker' sẽ giữ công nhân cuối cùng được chia hai, không phải mỗi người (đặc biệt bên trong sự kiện gọi lại). Hoặc bạn không quan tâm đến tất cả và bạn chỉ cần gửi kèm theo gọi lại của bạn hoặc bạn giữ tất cả các công nhân trong Array. – dresende

8

tôi thấy chủ đề này trong khi tìm kiếm một cách để gửi một thông điệp cho tất cả các quy trình con và đã may mắn có thể tìm ra nó nhờ vào các nhận xét về mảng. Chỉ muốn minh họa một giải pháp tiềm năng để gửi một thông điệp tới tất cả các tiến trình con sử dụng phương pháp này.

var cluster = require('cluster'); 
var http = require('http'); 
var numReqs = 0; 
var workers = []; 

if (cluster.isMaster) { 
    // Broadcast a message to all workers 
    var broadcast = function() { 
    for (var i in workers) { 
     var worker = workers[i]; 
     worker.send({ cmd: 'broadcast', numReqs: numReqs }); 
    } 
    } 

    // Fork workers. 
    for (var i = 0; i < 2; i++) { 
    var worker = cluster.fork(); 

    worker.on('message', function(msg) { 
     if (msg.cmd) { 
     switch (msg.cmd) { 
      case 'notifyRequest': 
      numReqs++; 
      break; 
      case 'broadcast': 
      broadcast(); 
      break; 
     } 
    }); 

    // Add the worker to an array of known workers 
    workers.push(worker); 
    } 

    setInterval(function() { 
    console.log("numReqs =", numReqs); 
    }, 1000); 
} else { 
    // React to messages received from master 
    process.on('message', function(msg) { 
    switch(msg.cmd) { 
     case 'broadcast': 
     if (msg.numReqs) console.log('Number of requests: ' + msg.numReqs); 
     break; 
    } 
    }); 

    // Worker processes have a http server. 
    http.Server(function(req, res) { 
    res.writeHead(200); 
    res.end("hello world\n"); 
    // Send message to master process 
    process.send({ cmd: 'notifyRequest' }); 
    process.send({ cmd: 'broadcast' }); 
    }).listen(8000); 
} 
3

Đây là cách tôi triển khai giải pháp cho một vấn đề tương tự. Bằng cách móc nối vào cluster.on('fork'), bạn có thể đính kèm trình xử lý tin nhắn cho người lao động khi họ được chia nhỏ (thay vì lưu trữ chúng trong một mảng), có lợi thế hơn trong việc xử lý các trường hợp người lao động chết hoặc ngắt kết nối và nhân viên mới được chia nhỏ.

Đoạn mã này sẽ gửi tin nhắn từ tổng thể tới tất cả công nhân.

if (cluster.isMaster) { 
    for (var i = 0; i < require('os').cpus.length; i++) { 
     cluster.fork(); 
    } 

    cluster.on('disconnect', function(worker) { 
     cluster.fork(); 
    } 

    // When a new worker process is forked, attach the handler 
    // This handles cases where new worker processes are forked 
    // on disconnect/exit, as above. 
    cluster.on('fork', function(worker) { 
     worker.on('message', messageRelay); 
    } 

    var messageRelay = function(msg) { 
     Object.keys(cluster.workers).forEach(function(id) { 
      cluster.workers[id].send(msg); 
     }); 
    }; 
} 
else { 
    process.on('message', messageHandler); 

    var messageHandler = function messageHandler(msg) { 
     // Worker received message--do something 
    }; 
} 
1

Tôi hiểu mục đích phát sóng cho tất cả các quy trình công nhân nút trong cụm, mặc dù bạn không thể gửi thành phần ổ cắm như vậy nhưng có một công việc xung quanh cho mục đích được phục vụ. Tôi sẽ cố gắng một giải thích với một ví dụ:

Bước 1: Khi một hành động của khách hàng đòi hỏi một phát sóng:

Child.js (Process that has been forked) : 

socket.on("BROADCAST_TO_ALL_WORKERS", function (data) 
{ 
    process.send({cmd : 'BROADCAST_TO_ALL_WORKERS', message :data.message}); 
}) 

Bước 2: Về mặt tạo cụm

Server.js (Place where cluster forking happens): 

if (cluster.isMaster) { 

    for (var i = 0; i < numCPUs; i++) { 

var worker = cluster.fork();

worker.on('message', function (data) { 
    if (data.cmd === "BROADCAST_TO_ALL_WORKERS") { 
     console.log(server_debug_prefix() + "Server Broadcast To All, Message : " + data.message + " , Reload : " + data.reload + " Player Id : " + data.player_id); 
     Object.keys(cluster.workers).forEach(function(id) { 
      cluster.workers[id].send({cmd : "BROADCAST_TO_WORKER", message : data.message}); 
     }); 
     } 
    }); 
    } 

    cluster.on('exit', function (worker, code, signal) { 
    var newWorker = cluster.fork(); 
    newWorker.on('message', function (data) { 
     console.log(data); 
     if (data.cmd === "BROADCAST_TO_ALL_WORKERS") { 
     console.log(data.cmd,data); 
     Object.keys(cluster.workers).forEach(function(id) { 
      cluster.workers[id].send({cmd : "BROADCAST_TO_WORKER", message : data.message}); 
     }); 
     } 
    }); 
    }); 
} 
else { 
    //Node Js App Entry 
    require("./Child.js"); 
} 

Bước 3: để phát sóng trong quá trình con -

-> Đặt điều này trước khi io.on ("kết nối") ở trẻ em.js

process.on("message", function(data){ 
    if(data.cmd === "BROADCAST_TO_WORKER"){ 
     io.sockets.emit("SERVER_MESSAGE", { message: data.message, reload: data.reload, player_id : data.player_id }); 
    } 
}); 

Tôi hy vọng điều này sẽ hữu ích. Vui lòng cho tôi biết nếu cần làm rõ thêm.

Các vấn đề liên quan