AWS应用程序负载平衡器和socket.io

我有一个socket.io聊天室,运行的stream量越来越大,因为我们在一台机器上运行。 我们使用ws库来运行基准testing,并且它们的性能会更好,这样可以更好地利用我们的硬件。 这将花费不得不重写我们的应用程序。

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

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

当一切都在一个实例中时,这很容易,但现在我们正在考虑将这个容量扩展到多个节点。

我们在亚马逊的云中运行这个实例。 以前它看起来像缩放websockets是ELBs的问题。 我们已经注意到,亚马逊现在支持和应用程序负载平衡器,它支持websockets。 这听起来不错,但是在阅读完文档之后,我必须承认我并不知道这意味着什么。 如果我使用带有数千个命名空间的socket.io,我只是将这个实例放在这个ALB的后面,一切都会运行?我的主要问题是:

如果x个用户join名称空间,ALB会自动将消息redirect到适当的用户,还是自己的用户? 假设我有5个vanilla socket.io实例在ALB后面运行。 用户1创build一个名称空间。 几个小时后,传递和用户99999来,并希望join这个命名空间,是否需要有任何额外的代码写这样做,或者白蛋白会redirect它应该去的一切? 发送和接收消息也是一样的吗?

虽然ALB会正确地对用户进行负载平衡,但您需要稍微调整一下您的代码,因为join特定会议室的用户将通过不同的服务器进行分散。

在他们的文档中, socket.io提供了一个这样的方法:

既然您有多个Socket.IO节点接受连接,如果您想要将事件广播给每个人(甚至某个房间的每个人),则需要在进程或计算机之间传递消息的方式。

负责路由消息的接口就是我们所说的Adapter。 您可以在socket.io适配器之上(通过inheritance它)实现自己的属性,也可以使用我们在Redis之上提供的一个:socket.io-redis:

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

ALB设置

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

在这里输入图像描述 在这里输入图像描述


使用不带socket.io适配器的ALB路由的备选scheme。

如果我想避免有一个redis数据库。 例如,如果我的房间是由用户创build的,如果userA在实例4上创build一个房间,如果另一个用户想要join这个房间,他们将如何知道它在哪个实例上? 我也需要这个适配器吗?

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

N个房间> 1个实例。

步骤1:

您需要将您的房间url更改为:

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

存在:

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

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

第2步:

创buildN个目标组(N代表您现在拥有的实例数量)

图片

第3步:

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

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

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

在这里输入图像描述

步骤4:

编辑ALB目标规则

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

在这里输入图像描述

第5步:

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

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

在这里输入图像描述


在这里输入图像描述

一旦你input了这个设置,

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

等等。

现在,您必须制定自己的逻辑,才能使房间平衡。 你不想让一个实例承载几乎所有的组。

我推荐第一种方法,因为它可以很容易地自动调整。