0

因此,我将尽我所能解释这一点:

我编写了一个 TCP 服务器,它接受来自可穿戴设备(gps 手环类型)的数据,使用netin NodeJS. 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部分给我带来了问题。

例如:当我curl -XPOST https://localhost:8080/send/device_id -d '{"command": "test"}'在 80% 的时间内使用时,这将转到错误的实例server.js,因为有五个server.js正在运行的副本,每个副本都有express服务器,并且由于 PM2 管理所有内容,我的请求将到达给定的tcp服务器device_id5 次中有 1 次连接。按照我的理解,PM2 启动 5 个实例,server.js并管理和平衡 和 的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);
});
4

1 回答 1

0

目前尚不清楚您是否计划将所有服务器实例作为工作人员在同一台服务器上运行,或者可能在多个节点上运行多个工作人员。

要更改的主要内容是您在实例中的状态存储。听起来您通过使用调用来存储每个工作人员的数据,connections[params.device_id]但如果这些集合存在于单个工作人员的内存中,那么就不知道彼此的数据或连接的其他套接字。

如果是这种情况,那么您需要将所有状态管理移至 Redis 等共享存储库。会话数据等也应该移动到中央仓库。最好对服务器进行架构设计,使它们尽可能无状态,这样您就可以根据需要启动任意数量的服务器。

确保您的应用程序是无状态的,这意味着进程中没有存储本地数据,例如会话/websocket 连接、会话内存和相关数据。使用 Redis、Mongo 或其他数据库在进程之间共享状态。

Socket.io 有一个redis-adapter来帮助促进 socket.io 实例之间的通信,以便它们了解套接字连接并帮助促进广播。

如果您在多台服务器上运行,那么您可能需要设置一些粘性会话,以便您最少被路由到同一台服务器。但是,如果实现上面建议的共享状态,那么这不是问题。如果那是不可能的,那么像express-sticky-cluster这样的包可能会有所帮助。

我自己的实现允许多个节点上的多个工作人员使用共享数据存储和 Redis 支持的适配器,这样即使客户端重新连接到不同的实例也不会产生影响。

希望有帮助!

更新 甚至有一个关于 PM2的指南指定了这个确切的架构。

于 2019-12-06T04:47:04.463 回答