与标准网络服务器一起将脱钩的实时服务器缩放



说我有一个为客户端提供标准HTML页面的典型Web服务器,并且与其一起运行的WebSocket服务器用于实时更新(聊天,通知等)。

。 。

我的一般工作流程是当主服务器上发生某些事情时,触发实时消息的需求时,主服务器将该消息发送到实时服务器(通过消息队列),而实时服务器将其分配给任何相关连接。

我担心的是,如果我想稍微扩展一些内容,并添加另一台实时服务器,看来我的唯一选择是:

  1. 有主服务器跟踪客户端的实时服务器已连接到。当该客户收到通知/聊天时消息,主服务器将消息转发到实时服务器客户端已连接到。不利的一面是代码复杂性,因为主服务器必须执行一些额外的书保持。
  2. 或拥有主服务器只需传递该消息到每个实时服务器;只有客户端的服务器是连接实际上会对它做任何事情。这将导致在传递的许多浪费消息中。

我在这里错过了另一个选择吗?我只是想确保我不会走太远这些途径,并意识到我在做错事。

如果场景是

a)主Web服务器在操作时发出消息(假设记录已插入)b)他通知适当的实时服务器

您可以使用将消息转发给指定收件人的中间酒吧/子体系结构将这两个步骤解除。

实现将是

1)您有一个redis pub-sub频道,在客户连接到实时插座的客户端,您开始在该频道中聆听

2)当主要应用程序要通过实时服务器通知用户时,它将频道推向消息,实时服务器获取IT并将其转发给预期的用户。

在这样您描述的问题是SignalR中使用的常见"消息背板",也与消息架构中的" fanout Message Exchange"有关。当拥有反平面或执行风扇时,每个消息都会转发到每个消息节点服务器,以便客户端可以连接到任何服务器并获取消息。当您必须同时支持长时间的投票和Websocket时,这种方法是一种合理的痛苦。但是,正如您注意到的那样,这是浪费流量和资源。

您需要使用具有智能路由的消息基础架构,例如RabbitMQ。看看主题和标题交换:https://www.rabbitmq.com/tutorials/amqp-concepts.html

主题如何交换路线消息

Windows的RabbitMQ:Exchange类型

有很多不同的排队框架。选择您喜欢的那个,但要确保您可以拥有更多的交换模式,而不是直接或粉丝;)最后,websocket是连接到消息基础架构的端点。因此,如果要扩大规模,它可以归结为您拥有的后端:)

对于几个实时服务器,您可以想象只能保留一个它们在主服务器中的列表,只需浏览它们。

另一种方法是使用负载平衡器。

基本上,您将有一个专用节点可以从主服务器接收请求,然后让该负载平衡器节点负责选择哪个Websocket/实时服务器将请求转发到。

当然,这只是将代码复杂性从主服务器转移到新组件,但我认为它更好,更脱钩。

更改了答案,因为答复表明"主"one_answers"实时"服务器是Alraady负载平衡群集,而不是单个主机。

中心可伸缩性问题似乎是:

我的一般工作流程是当主服务器上发生某些事情时,触发实时消息的需求时,主服务器将该消息发送到实时服务器(通过消息队列),而实时服务器将其分配给任何相关连接。

强调"相关"一词。假设您有10个"主"服务器和50个"实时"服务器,并且在主服务器上发生了一个事件:哪些WebSocket将被视为与此事件有关的?

最坏的情况是,任何"主"服务器上的任何事件都需要传播到所有Websockets。这是O(n^2)的复杂性,这算作严重的可伸缩性障碍。

只有在不随着群集大小或总nr而生长的组中的相关连接时,才能防止此O(n^2)的复杂性。连接。分组需要状态内存才能存储到一个连接所属的组。

请记住,有3种存储状态的方法:

  1. 全局内存(Memcached/redis/db,...)
  2. 粘性路由(负载平衡器配置)
  3. 客户端内存(cookie,浏览器本地存储,链接/重定向URL)

,选项3将其视为最可扩展的,因为它省略了中央状态存储。

为了将消息从"主"传递到"实时"服务器,该流量应比对客户的流量小得多。还有有效的框架来推出酒吧/子流量。

最新更新