Socket.io 通过 pm2 使用多个节点时不工作
Socket.io not working when using multiple nodes through pm2
我有 NodeJS 应用程序 运行 Socket.io 用于实时更新。我在生产 Node.js 应用程序中使用 PM2 流程管理器。现在我想在PM2中使用集群模式。
由于 nodejs 应用程序在单个进程中运行,我想利用我的服务器系统上可用的 max cpu 。目前我的系统有 4 个核心。所以使用 PM2 集群模式,我可以利用所有核心,PM2 将在幕后自行处理所有事情。
当使用单个服务器实例时,我的 nodejs 应用 socket.io 与客户端一起工作正常。
但是当我使用集群模式时,PM2 会启动 4 个服务器实例。我尝试连接多个客户端(通过打开多个终端和 运行 客户端部分),它们成功连接了 PM2 以随机方式启动的实例,这是预期的并且很好。
我想做什么?
- 使用集群模式启动 pm2
- 客户端可以通过 pm2
连接任何已启动的实例
- 客户端连接后,Server-1 将发出应该发送给连接到所有服务器的所有客户端的事件
- 在成功测试以上步骤后,我将整合房间的逻辑,但由于我在步骤 3 中没有成功,所以我不会进行 setp 4。
我的问题是,当我想从服务器 1 向客户端发出事件时,它应该发送到所有连接到所有 4 个服务器实例(服务器 1、服务器 2、服务器 3、服务器- PM2 启动了 4 个实例)。
但是每当我从 server-1 发出事件时,它只会发送到仅连接到 server-1 的客户端。
我在服务器日志中收到错误,
You have triggered an unhandledRejection, you may have forgotten to catch a Promise rejection:
Error: The client is closed
at Commander._RedisClient_sendCommand (/var/www/html/test/server-socket/node_modules/@node-redis/client/dist/lib/client/index.js:387:31)
at Commander.commandsExecutor (/var/www/html/test/server-socket/node_modules/@node-redis/client/dist/lib/client/index.js:160:154)
at Commander.BaseClass.<computed> [as publish] (/var/www/html/test/server-socket/node_modules/@node-redis/client/dist/lib/commander.js:8:29)
at RedisAdapter.broadcast (/var/www/html/test/server-socket/node_modules/@socket.io/redis-adapter/dist/index.js:374:28)
at BroadcastOperator.emit (/var/www/html/test/server-socket/node_modules/socket.io/dist/broadcast-operator.js:109:22)
at Namespace.emit (/var/www/html/test/server-socket/node_modules/socket.io/dist/namespace.js:170:73)
at Server.<computed> [as emit] (/var/www/html/test/server-socket/node_modules/socket.io/dist/index.js:576:33)
at Timeout._onTimeout (/var/www/html/test/server-socket/index.js:25:16)
at listOnTimeout (internal/timers.js:549:17)
at processTimers (internal/timers.js:492:7)
index.js(服务器端)
const { Server } = require("socket.io")
const { createAdapter } = require("@socket.io/redis-adapter");
const { createClient } = require("redis");
const io = new Server({ transports: ['websocket'] })
const pubClient = createClient({ host: 'localhost', port: 6379, auth_pass: "root" });
const subClient = pubClient.duplicate();
subClient.psubscribe = pubClient.pSubscribe
io.adapter(createAdapter(pubClient, subClient))
io.listen(3000)
// console.log('process.env.NODE_APP_INSTANCE: ' + process.env.NODE_APP_INSTANCE);
io.on("connection", (socket) => {
console.log(socket.id + ' connected on server: ' + process.env.NODE_APP_INSTANCE)
// emitting event from only server-1 to test whether all client gets it or not
if(process.env.NODE_APP_INSTANCE == 0){
setInterval(() => {
io.emit('test_msg', 'server: ' + process.env.NODE_APP_INSTANCE)
}, 5000)
}
});
index.js(在客户端)
const { io } = require("socket.io-client");
const socket = io("http://localhost:3000", {
transports: ["websocket"]
});
socket.on("connect", () => {
console.log(socket.id + ' connected with server')
})
socket.on("test_msg", (data) => {
console.log('test_msg caught: ' + data)
})
ecosystem.config.js 文件(在 pm2 的服务器端)
module.exports = {
apps : [{
name: 'server-socket',
script: 'index.js',
watch: '.',
// instances : "max",
instances : 4,
exec_mode : "cluster",
increment_var : 'PORT',
env_development: {
PORT: 3000,
NODE_ENV: "development"
},
env_production: {
NODE_ENV: "production"
},
}]
};
我用过的套餐:
"@socket.io/redis-adapter": "^7.0.1",
"nodemon": "^2.0.15",
"redis": "^4.0.0",
"socket.io": "^4.4.0"
"socket.io-client": "^4.4.0" // this package used at client side
NodeJs version: v12.16.1
NPM version: v6.13.4
PM2 version: v5.1.2
我正在关注来自 here
的文档 (socket.io)
我不知道那个错误是什么意思,但我花了很多时间尝试了很多东西,但还没有发现任何有用的东西。
- 任何人都可以用示例代码或解决方案指导我吗?
我认为这是因为必须先手动连接 redis@4 客户端:
Promise.all([pubClient.connect(), subClient.connect()]).then(() => {
io.adapter(createAdapter(pubClient, subClient));
io.listen(3000);
});
我有 NodeJS 应用程序 运行 Socket.io 用于实时更新。我在生产 Node.js 应用程序中使用 PM2 流程管理器。现在我想在PM2中使用集群模式。 由于 nodejs 应用程序在单个进程中运行,我想利用我的服务器系统上可用的 max cpu 。目前我的系统有 4 个核心。所以使用 PM2 集群模式,我可以利用所有核心,PM2 将在幕后自行处理所有事情。
当使用单个服务器实例时,我的 nodejs 应用 socket.io 与客户端一起工作正常。 但是当我使用集群模式时,PM2 会启动 4 个服务器实例。我尝试连接多个客户端(通过打开多个终端和 运行 客户端部分),它们成功连接了 PM2 以随机方式启动的实例,这是预期的并且很好。
我想做什么?
- 使用集群模式启动 pm2
- 客户端可以通过 pm2 连接任何已启动的实例
- 客户端连接后,Server-1 将发出应该发送给连接到所有服务器的所有客户端的事件
- 在成功测试以上步骤后,我将整合房间的逻辑,但由于我在步骤 3 中没有成功,所以我不会进行 setp 4。
我的问题是,当我想从服务器 1 向客户端发出事件时,它应该发送到所有连接到所有 4 个服务器实例(服务器 1、服务器 2、服务器 3、服务器- PM2 启动了 4 个实例)。
但是每当我从 server-1 发出事件时,它只会发送到仅连接到 server-1 的客户端。
我在服务器日志中收到错误,
You have triggered an unhandledRejection, you may have forgotten to catch a Promise rejection:
Error: The client is closed
at Commander._RedisClient_sendCommand (/var/www/html/test/server-socket/node_modules/@node-redis/client/dist/lib/client/index.js:387:31)
at Commander.commandsExecutor (/var/www/html/test/server-socket/node_modules/@node-redis/client/dist/lib/client/index.js:160:154)
at Commander.BaseClass.<computed> [as publish] (/var/www/html/test/server-socket/node_modules/@node-redis/client/dist/lib/commander.js:8:29)
at RedisAdapter.broadcast (/var/www/html/test/server-socket/node_modules/@socket.io/redis-adapter/dist/index.js:374:28)
at BroadcastOperator.emit (/var/www/html/test/server-socket/node_modules/socket.io/dist/broadcast-operator.js:109:22)
at Namespace.emit (/var/www/html/test/server-socket/node_modules/socket.io/dist/namespace.js:170:73)
at Server.<computed> [as emit] (/var/www/html/test/server-socket/node_modules/socket.io/dist/index.js:576:33)
at Timeout._onTimeout (/var/www/html/test/server-socket/index.js:25:16)
at listOnTimeout (internal/timers.js:549:17)
at processTimers (internal/timers.js:492:7)
index.js(服务器端)
const { Server } = require("socket.io")
const { createAdapter } = require("@socket.io/redis-adapter");
const { createClient } = require("redis");
const io = new Server({ transports: ['websocket'] })
const pubClient = createClient({ host: 'localhost', port: 6379, auth_pass: "root" });
const subClient = pubClient.duplicate();
subClient.psubscribe = pubClient.pSubscribe
io.adapter(createAdapter(pubClient, subClient))
io.listen(3000)
// console.log('process.env.NODE_APP_INSTANCE: ' + process.env.NODE_APP_INSTANCE);
io.on("connection", (socket) => {
console.log(socket.id + ' connected on server: ' + process.env.NODE_APP_INSTANCE)
// emitting event from only server-1 to test whether all client gets it or not
if(process.env.NODE_APP_INSTANCE == 0){
setInterval(() => {
io.emit('test_msg', 'server: ' + process.env.NODE_APP_INSTANCE)
}, 5000)
}
});
index.js(在客户端)
const { io } = require("socket.io-client");
const socket = io("http://localhost:3000", {
transports: ["websocket"]
});
socket.on("connect", () => {
console.log(socket.id + ' connected with server')
})
socket.on("test_msg", (data) => {
console.log('test_msg caught: ' + data)
})
ecosystem.config.js 文件(在 pm2 的服务器端)
module.exports = {
apps : [{
name: 'server-socket',
script: 'index.js',
watch: '.',
// instances : "max",
instances : 4,
exec_mode : "cluster",
increment_var : 'PORT',
env_development: {
PORT: 3000,
NODE_ENV: "development"
},
env_production: {
NODE_ENV: "production"
},
}]
};
我用过的套餐:
"@socket.io/redis-adapter": "^7.0.1",
"nodemon": "^2.0.15",
"redis": "^4.0.0",
"socket.io": "^4.4.0"
"socket.io-client": "^4.4.0" // this package used at client side
NodeJs version: v12.16.1
NPM version: v6.13.4
PM2 version: v5.1.2
我正在关注来自 here
的文档 (socket.io)我不知道那个错误是什么意思,但我花了很多时间尝试了很多东西,但还没有发现任何有用的东西。
- 任何人都可以用示例代码或解决方案指导我吗?
我认为这是因为必须先手动连接 redis@4 客户端:
Promise.all([pubClient.connect(), subClient.connect()]).then(() => {
io.adapter(createAdapter(pubClient, subClient));
io.listen(3000);
});