node.js - AWS 应用程序负载均衡器和 socket.io

标签 node.js amazon-ec2 websocket socket.io amazon-elb

我有一个正在运行的 socket.io 聊天室,当我们在一台机器上运行时,它的流量越来越大。我们已经使用 ws 库对套接字进行了基准测试,它们的性能确实要好得多,这将更好地利用我们的硬件。不过,这将以不得不重写我们的应用程序为代价。

我们的 socket.io 应用程序允许用户创建使用命名空间实现的私有(private)聊天室。例如

localhost:8080/room/1
localhost:8080/room/2
localhost:8080/room/3

当一切都在一个实例中时,这很容易,但现在我们正在寻求将这种能力扩展到多个 Node 。

我们在亚马逊的云中运行这个实例。以前看起来扩展 websocket 是 ELB 的一个问题。我们注意到亚马逊现在支持支持 websockets 的应用程序负载均衡器。这听起来不错,但是在阅读了文档之后,我必须承认我真的不知道这意味着什么。如果我使用带有数千个命名空间的 socket.io,我是否只需将实例放在此 ALB 后面,一切都会正常工作?我的主要问题是:

如果 x 数量的用户加入命名空间,ALB 是否会自动将我的消息重定向到正确的用户或从正确的用户重定向?因此,假设我在 ALB 后面运行了 5 个 vanilla socket.io 实例。用户 1 创建一个命名空间。几个小时后过去了,用户 99999 来并想要加入这个命名空间,是否需要编写任何额外的代码来执行此操作,或者 alb 是否会将所有内容重定向到它应该去的地方?发送和接收消息也是如此?

最佳答案

虽然 ALB 会正确地对用户进行负载平衡,但您需要稍微调整您的代码,因为加入特定房间的用户将分散在不同的服务器中。

在他们的documentation socket.io 提供了一种方法来做到这一点:

Now that you have multiple Socket.IO nodes accepting connections, if you want to broadcast events to everyone (or even everyone in a certain room) you’ll need some way of passing messages between processes or computers.

The interface in charge of routing messages is what we call the Adapter. You can implement your own on top of the socket.io-adapter (by inheriting from it) or you can use the one we provide on top of Redis: socket.io-redis:

var io = require('socket.io')(3000);
var redis = require('socket.io-redis');
io.adapter(redis({ host: 'localhost', port: 6379 }));

ALB 设置

我建议在您的 ALB 中启用 sticky session,否则在使用非 websocket 传输(例如长轮询)时,socket.io 握手将失败,因为使用此传输的握手任务需要超过一个请求,您需要针对同一台服务器执行所有这些请求。

enter image description here enter image description here


在没有 socket.io 适配器的情况下使用 ALB 路由的替代方法。

If I wanted to avoid having a redis database. For example, if my rooms are created by users, if userA creates a room on instance 4, if another user wants to join this room, how would they know which instance it is on? Would I need the adapter here too?

此替代方案的目标是将每个房间分配给特定的 EC2 实例。我们将使用 ALB Routing 来实现这一点

N 个房间 > 1 个实例。

第 1 步:

您需要将房间 URL 更改为:

/i1/room/550
/i1/room/20
/i2/room/5
/i5/room/492

存在:

/{instance-number}/room/{room-id}

这是必需的,以便 ALB 可以将每个房间路由到特定实例。

第 2 步:

创建 N 个目标组(N 是您目前拥有的实例数)

Image

第三步:

将每个实例注册到每个目标组

目标组 > 实例 X 目标组 > 目标选项卡 > 编辑 > 选择实例 X > 添加到已注册

Target group X > EC2 Instance X
Target group Y > EC2 Instance Y

enter image description here

第四步:

编辑 ALB 目标规则

负载均衡器 > 您的 ALB > 监听器 > 查看/编辑规则

enter image description here

第五步:

使用以下设置为每个目标组/实例创建一条规则:

  • IF > 路径: /iX/room/*
  • THEN > 转发到: instanceX

enter image description here


enter image description here

一旦您在进入时进行此设置:

  • /i1/room/550您将使用 EC2 实例 1。
  • /i2/room/200 将使用 EC2 实例 2

等等。

现在您必须制定自己的逻辑,以使房间在您的实例之间保持平衡。 您不想让一个实例托管几乎所有组。

我推荐第一种方法,因为它可以轻松自动缩放。

关于node.js - AWS 应用程序负载均衡器和 socket.io,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43702043/

相关文章:

php - 使用 PHP 和 Symfony 的 Websockets - 网络和服务器架构

websocket - 错误 ServerMiddleware 应公开句柄 nuxt

javascript - 在Java中生成唯一键

node.js - NodeJS类结构中的MongoDB

amazon-ec2 - ecs docker容器中celery worker的奇怪行为

amazon-web-services - Amazon AWS 自动缩放 leader_only 属性

javascript - 如何在nodejs中使用url获取文件大小

node.js - 如何在 node.js 中接收 socket.io 客户端事件?

amazon-ec2 - EC2 用于处理需求高峰

javascript - Chrome 在从 libwebsockets 接收时说 "Could not decode a text frame as UTF-8"