处理多个实例上的 WebSocket 连接。

3
我需要理解在多个实例上处理WebSockets的概念,以便可以在所有实例之间共享。例如,我有三个正在运行的节点,由负载均衡器连接。在接收到需要在特定套接字上发出的数据时,我的最初想法是创建哈希映射或JSON对象来保存WebSocket连接。但是我意识到这不能以这种方式完成,因为它仅适用于特定实例。如果我在任何一个实例上接收到数据,那么大部分数据将不会发出到该WebSocket连接,因为它不知道WebSocket是在哪个实例上创建的。有没有一种好的方法来处理WebSocket连接,使其可以在所有实例上共享。我的想法是使用Redis或PostgreSQL数据库,因为它们在所有实例之间共享。
此外,我已经尝试过使用PostgreSQL解决方案来存储WebSocket连接,但当我保存连接时,它显示
TypeError: Converting circular structure to JSON
是否有一些好的解决方案来处理可以在所有实例之间共享的WebSocket连接。如果数据库是一个好的解决方案,我应该如何解决TypeError:Converting circular structure to JSON问题。
1个回答

0

我猜你正在寻找的是 适配器,它在官方的 socket.io 文档中有比较好的记录(/v4/adapter/)。

当扩展到多个 Socket.IO 服务器时,您需要用另一种实现替换默认的内存适配器,以便事件正确路由到所有客户端。

您可以选择几个官方适配器:

  • Redis 适配器
  • MongoDB 适配器
  • Postgres 适配器
  • Cluster 适配器

这里是使用 MongoDB 适配器的示例:

npm install @socket.io/mongo-adapter mongodb

const { Server } = require("socket.io");
const { createAdapter } = require("@socket.io/mongo-adapter");
const { MongoClient } = require("mongodb");

// DATABASE CONNECTION
const DB = "mydb";
const COLLECTION = "socket.io-adapter-events";
const mongoClient = new MongoClient("mongodb://localhost:27017/?replicaSet=rs0", {
  useUnifiedTopology: true,
});

const io = new Server();

const main = async () => {
  await mongoClient.connect();

  try {
    await mongoClient.db(DB).createCollection(COLLECTION, {
      capped: true,
      size: 1e6
    });
  } catch (e) {
    // collection already exists
  }
  const mongoCollection = mongoClient.db(DB).collection(COLLECTION);

  // HERE COMES THE IMPORTANT PART :)
  // CREATE MONGO DB ADAPTER AND USE IT 
  io.adapter(createAdapter(mongoCollection));
  io.listen(3000);
}

main();

适配器将会处理剩下的部分。每个发送给多个客户端的数据包(例如io.to("room1").emit()socket.broadcast.emit())都会:
  • 发送到所有连接到当前服务器的匹配客户端
  • 插入到MongoDB的固定集合中,并被集群中其他Socket.IO服务器接收

谢谢您提供这么详细的答案。我有一个问题,Bull队列可以作为解决方案吗?因为它也连接到Redis,并且Bull队列可以将消息发布到所有实例中吗? - JN_newbie
bull-queue 用于创建队列,例如任务队列(这样进程可以逐个处理它们...)。是的,bull-queue 还利用了 Redis,因此我想跨多个节点拥有一个队列是可能的,Redis 将使它们保持同步。不幸的是,这与 socket.io 没有任何关系。你在使用 socket.io 的情况是什么?也许我错过了什么。 - Pascal Lamers
再次感谢。实际上,我正在从一个服务器获取实时数据。我想处理这些数据并将其发送到用户设备。因此,我认为套接字是一个很好的解决方案,因为用户可以在多个设备上登录并拥有自己的套接字连接,然后它的数据可以在所有设备之间同步。对于本地环境来说,它运行良好,但在我们的分布式环境中,它无法正常工作,因为有时实时数据会到达instance1,有时到达instance2,如果套接字连接在instance1上而数据到达instance2,则无法接收。 - JN_newbie
现在为了解决这个问题,我正在考虑一些排队机制或者你在答案中提出的建议。 - JN_newbie
数据有时会被发送到instance1,有时会被发送到instance2,这完美地描述了多节点socket.io集群的问题。默认情况下,一个socket.io节点不知道其他socket.io节点及其连接的任何信息,这就是其中一种适配器发挥作用的地方。当所有socket.io连接在所有socket.io节点上同步时,您可以将所有这些用户的socket连接保存在1个socket.io房间中,然后只需向该房间发送数据。我自己没有使用过多节点socket.io设置,这只是我的想法。 - Pascal Lamers
是的,我现在需要按照你在答案中提出的建议进行工作。我会尝试一下并告诉你结果 :) - JN_newbie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接