因此,我将尽我所能尝试对此进行解释:
我编写了一个TCP服务器,该服务器使用net
中的NodeJS
从可穿戴设备(gps手镯类型)接收数据。 TCP服务器具有connections = {}
属性,其中包含所有连接,如下所示:
device id
connections[device_id] = socket
同一TCP服务器还具有express
服务器,该服务器允许我使用JSON post:curl -XPOST https://localhost:8080/send/device_id -d '{"command": "test"}'
服务器解析URL,然后使用connections[params.device_id].write()
使用pm2 start server.js
时,一切正常。我能够跟踪设备,接受和发送数据等。
问题是,当我在群集模式下使用pm2 start -i 5 server.js
启动服务器时,设备连接可以正常工作,但是express
部分给了我麻烦。
例如:当我在80%的时间内使用curl -XPOST https://localhost:8080/send/device_id -d '{"command": "test"}'
时,它将转到错误的server.js
实例,因为有server.js
的五个副本在运行,并且每个副本都有express
服务器,并且由于PM2可以管理所有内容,因此我的请求将到达tcp
服务器,其中给定的device_id
在5次中有1次连接。以我的理解,PM2启动server.js
的5个实例,并管理和平衡tcp
和express
的连接。
所以,我的问题是,我应该如何处理?有没有办法告诉PM2将端口8080
转发到集群中所有正在运行的实例?这样,我可以向所有实例发送单个命令,然后在实例中检查device_id是否已连接,并写入其套接字。
这可能吗?如果可以,这是个好主意吗?如果没有,那么正确的方法是什么?
希望我能解释
致谢
*编辑*
从最初的问题可能不清楚,但是有问题的socket
是通过net.createServer
函数传递的,例如
const net = require('net');
const PORT = 8181;
let connections = {}
const server = net.createServer((c) => {
//... device id parse
connections[device_id] = c;
});
server.listen(PORT, () => {
console.log('Server started on', PORT);
});
答案 0 :(得分:0)
尚不清楚您是打算将所有服务器实例作为工作程序运行在同一服务器上,还是可能在多个节点上运行多个工作程序。
要更改的主要内容是实例中的状态存储。听起来好像您正在通过使用connections[params.device_id]
之类的调用来为每个工作人员存储数据,但是如果这些集合存在于单个工作人员的内存中,则不会知道彼此的数据或所连接的其他套接字。
如果是这种情况,那么您需要将所有状态管理移至Redis这样的共享存储库。会话数据等也应移至中央存储库。最好对服务器进行架构设计,以使它们尽可能处于无状态,以便您可以根据需要启动尽可能多的服务器。
确保您的应用程序是无状态的,这意味着没有本地数据 存储在进程中,例如会话/ Websocket连接, 会话内存和相关。使用Redis,Mongo或其他数据库来 在进程之间共享状态。
Socket.io具有redis-adapter,可帮助促进socket.io实例之间的通信,以便它们知道套接字连接并有助于广播。
如果您在多台服务器上运行,则可能需要设置一些粘性会话,以便最少将您路由到同一台服务器。但是,如果上面建议了实现共享状态,那么这不是问题。如果这不可能,那么也许像express-sticky-cluster这样的软件包可能会有所帮助。
我自己的实现允许使用共享数据存储和Redis支持的适配器在多个节点上有多个工作线程,因此如果客户端重新连接到其他实例,这不会有任何不同。
希望有帮助!
更新 在PM2上甚至有一个guideline指定了这种确切的体系结构。