我們都知道 Node 沒法操作線程,但可以操作進程,一旦涉及主從模式的進程守護,或者是多機部署的需要,那么都可能碰上需要相互通信的場景,本篇就介紹幾種常用方法。
Node 原生 IPC(Inter-Process Communication,進程間通信)支持
最自然的方式,比上一種“正規”一些,具有同樣的局限性。其底層是 libuv。
父
// parent.js
const cp = require('child_process');
const n = cp.fork(`child.js`);
n.on('message', (m) => {
console.log('父進程收到消息', m);
});
// 使子進程輸出: 子進程收到消息 { hello: 'world' }
n.send({ hello: 'world' });
子
// child.js
process.on('message', (m) => {
console.log('子進程收到消息', m);
});
// 使父進程輸出: 父進程收到消息 { foo: 'bar', baz: null }
process.send({ foo: 'bar', baz: NaN });
運行
> node parent.js
子進程收到消息 { hello: 'world' }
父進程收到消息 { foo: 'bar', baz: null }
libuv 的進程通信能力是怎么來的?
這就要涉及到操作系統的進程間通信方式了,參見深刻理解Linux進程間通信(IPC)。進程間通信一般通過共享內存的方式實現的,使得多個進程可以訪問同一塊內存空間,是最快的可用 IPC 形式。
通過 sockets
最通用的方式,借助網絡完成進程通信,有良好的跨環境能力,但存在網絡的性能損耗。
父
// parent.js
const { spawn } = require('child_process');
const child = spawn('node', ['child'], {
stdio: [null, null, null, 'pipe'],
});
child.stdio[3].on('data', data => {
console.log('222', data.toString());
});
子
// child.js
const net = require('net');
const pipe = net.Socket({ fd: 3 });
pipe.write('killme');
運行
> node parent.js
222 killme
消息隊列
最強大的方式,既然要通信,場景還復雜,不妨擴展出一層消息中間件,漂亮地解決各種通信問題.
消息隊列可以參見 Rabitmq
或者使用 Redis 的訂閱發布,見下例
父
// parent.js
const cp = require('child_process');
const child = cp.fork(`child.js`);
var Redis = require("ioredis");
var redis = new Redis();
var pub = new Redis();
// 訂閱 news 通道,
redis.subscribe("news", function (err, count) {
// `count` represents the number of channels we are currently subscribed to.
});
// 監聽 message 事件。
redis.on("message", function (channel, message) {
// Receive message Hello world! from channel news
// Receive message Hello again! from channel music
console.log("Receive message %s from channel %s", message, channel);
}
子
// child.js
var Redis = require("ioredis");
var pub = new Redis();
// 發布新消息
pub.publish("news", "Hello world!");
pub.publish("music", "Hello again!");
總結
單機使用則直接 Node 原生 IPC 最為省事,就如 EggJS 中 Master 進程與 Worker 進程的通信。
但你的服務負載需要部署去了多台機器,筆者更建議使用消息隊列的方式來相互通信,畢竟追蹤多機的 websocket 鏈路,是挺頭疼的一件事。