2015-05-08 56 views
2

假设我有一个典型的Web服务器,它向客户端提供标准的HTML页面,并且与它一起运行的websocket服务器用于实时更新(聊天,通知等)。扩展标准的网络服务器旁边的解耦实时服务器

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

我担心的是,如果我想扩大了一点东西,并添加另一个实时服务器,似乎我唯一的选择是:

  1. 有主服务器跟踪哪些实时服务器的客户端 连接到。当客户端收到通知/消息 消息时,主服务器将该消息转发给客户端连接的实时服务器 。这里的缺点是代码复杂度为 ,因为主服务器必须做一些额外的预订 保留。
  2. 或者,主服务器只需将该消息 一起传递给每个实时服务器;只有连接到客户端的服务器 实际上会对它做任何事情。这会导致 被大量浪费的消息传递。

我在这里错过了另一个选择吗?我只是试图确保我不会在这些路径中走得太远,并意识到我正在做的事情完全错误。

+0

您也可以使用像pusher.com或realtime.co这样的实时云服务。他们会为你处理重负载,你不需要担心可扩展性。永远。 –

+0

@JoãoParreira - 希望避免外部解决方案。我已经有了一个可以正常工作的系统,我只是因为好奇而感兴趣。 – repole

回答

1

如果方案是

一)主要的Web服务器时的操作提出了一个消息(比方说,一个记录插入) b)他通知相应的实时服务器

你可以通过使用中间pub/sub架构将这些消息转发给接收者来解耦这两个步骤。

的实现将是

1)您有其中在连接到一个实时插座一个客户,你开始在该通道中

2)当主应用程序侦听Redis的发布 - 订阅通道想要通过实时服务器通知用户,它会向该通道推送一条消息,实时服务器获取该消息并将其转发给目标用户。

通过这种方式,您可以将实时通知从主应用程序中分离出来,并且不必跟踪用户的位置。

+0

Pub-sub听起来像我正在寻找的东西,它并没有告诉我,我可以使用一个频道来说每个客户端,而不是每个服务器的频道。欣赏故障。 – repole

+0

@repole如果您在websocket服务器前使用类似haproxy的东西,您可以实现实时组件的横向可伸缩性,与主服务器分开 –

0

对于少数几台实时服务器,您可以想象,只需在主服务器上保存一份它们的列表,然后通过它们轮询即可。其他方法是使用load balancer

基本上,您将有一个专用节点来接收来自主服务器的请求,然后让该负载均衡器节点负责选择将请求转发给哪个websocket /实时服务器。

当然,这只是将代码复杂度从主服务器转移到新的组件,但从概念上讲,我认为它更好,更分离。

+0

但即使使用负载均衡器,问题在于每个客户端仍然最终连接到该负载均衡器后面的潜在许多实时服务器之一。我留在我的问题中描述的完全相同的情况下,我必须跟踪客户端实际连接到哪个实时服务器,或者我仍然必须发送任何消息到每个实时服务器 – repole

0

更改了答案,因为答复表明“主”和“实时”服务器是已建立负载平衡的群集,而不是单个主机。

中心的可扩展性问题似乎是:

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

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

最糟糕的情况是任何“主”服务器上的任何事件都需要传播到所有websocket。这是O(N^2)的复杂性,这被视为严重的可扩展性损害。

如果您可以将相关的连接分组为不与群集大小或总数nr一起增长的群组,则只能防止O(N^2)复杂度。的连接。分组需要状态存储器来存储连接所属的组。

请记住,有3种方式来存储状态:

  1. 全局内存(memcached的/ Redis的/ DB,...)
  2. 粘路由(负载平衡器配置)
  3. 客户端内存(饼干,浏览器本地存储,链接/重定向URL)

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

为了将消息从“主”传递到“实时”服务器,根据定义,该流量应该远小于流向客户端的流量。还有高效的框架来推动pub/sub流量。

+0

我不是说“主“服务器就好像只有一个。其目的是将多个主服务器放在负载平衡器后面,并将多个实时服务器放在负载平衡器后面。 耦合实时服务器和主服务器可能会起作用,但它似乎仍然不完美,因为一个人更可能需要处理更大的负载,因此将它们耦合起来会是浪费。但或许这样做比起将消息分发到每个实时服务器,或者不得不做记录来知道客户端连接到哪个服务器要浪费得多。 – repole

1

您所描述的问题是在SignalR中使用的常见“消息背板”,也与消息体系结构中的“扇出消息交换”有关。当有背板或扇出时,每条消息都被转发到每个消息节点服务器,因此客户端可以连接到任何服务器并获取消息。当你必须同时支持长轮询和websocket时,这种方法是合理的。但是,正如您注意到的那样,这是浪费流量和资源。

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

How Topic Exchanges Route Messages

RabbitMQ for Windows: Exchange Types

有吨不同的排队框架。选择一个你喜欢的,但确保你可以有更多的交换模式,而不仅仅是直接或扇出;)最后,WebSocket只是和端点连接到消息基础设施。所以,如果你想进行扩展,把它归结为后端你:)