3

我正在尝试构建一个包含即时消息传递模块的应用程序,主要挑战之一是保持应用程序可扩展,无论用户数量或交换的消息是多少。

一篇文章中,我读到可以使用带有“订阅”的 GraphQL 构建实时应用程序,除此之外,它使用起来很简单,并且具有最小化往返对象检索的优点,因此资源使用更少。

但是如果我们需要向系统添加一个新的服务器/节点以便水平扩展呢?这可能使用 GraphQL 吗?

以允许水平缩放的 websockets 实现为例,有SocketCluster。我想知道单独由 GraphQL 开发的应用程序是否可以跨多个节点/机器进行扩展,或者它必须与另一个框架(如 SocketCluster)一起使用才能实现这一目标。

4

1 回答 1

5

很快——是的。我们已经做到了,而且效果很好。

诀窍是,当涉及到水平扩展时,您必须比 API 工作者应用程序更深入地思考。如果你想要推送架构,从一开始就需要异步

为了实现它,我们使用了队列系统,即RabbitMQ

想象一下这种生成报告的场景,这可能需要 10 分钟:

  1. 客户端通过 WebSocket 连接到我们的 GraphQL API(实例 1)
  2. 客户端通过 WebSocket 发送命令生成报告
  3. API 为命令生成令牌并将生成报告的命令放入 CommandQueue(在 RabbitMQ 中),将令牌返回给客户端。
  4. 客户端使用令牌订阅其命令结果的事件
  5. 一些后端 Worker 拿起命令并执行报告生成过程
  6. 在此期间 GraphQL API(实例 1)死亡
  7. 客户端自动重新连接到 GraphQL API(实例 2)
  8. 客户端使用之前获取的令牌续订订阅
  9. Worker 完成,EventsQueue (RabbitMQ) 上的结果
  10. 我们所有的 GraphQL 实例都会收到关于 的信息ReportGenerationDoneEvent并检查是否有人在监听它的令牌。
  11. GraphQL API(实例 2)看到客户端正在等待结果。通过 websockets 推送结果。
  12. GraphQL API(实例 3-100)忽略ReportGenerationDoneEvent.

它相当广泛,但通过简单的抽象,您不必考虑所有这些复杂性,并跨多个服务编写约 30 行代码,用于使用此路由的新流程。

它的精彩之处在于,您最终获得了很好的水平扩展、事件可重播性(重试)、关注点分离(客户端、api、工作人员),尽可能快地将数据推送到客户端,正如您提到的那样不要在are we done yet?请求上浪费带宽。

另一个很酷的事情是,每当用户在我们的面板中打开报告列表时,他会看到当前正在生成的报告,并且可以订阅他们的更改,因此他们不必手动刷新列表。

对 SocketCluster 的好思考。它将优化上述场景中的第 10 步,但目前,我们没有看到将其广播ReportGenerationDoneEvent到整个 API 集群的任何性能问题。对于更多实例或多区域架构,这将是必须的,因为它可以实现更好的扩展和分片。

重要的是要了解 SocketCluster 在通信层(WebSockets)上运行,但逻辑 API 层(GraphQL)在其之上。要进行 GraphQL 订阅,您只需使用允许您向用户推送信息的通信协议,而 WebSockets 允许这样做。

我认为使用 SocketCluster 是一个不错的设计选择,但请记住迭代实现。仅当您计划在任何单个时间点打开多个套接字时才使用 SocketCluster。此外,您应该仅在必要时订阅,因为 WebSocket 是有状态的并且需要管理和心跳。

如果您对我上面使用的异步后端架构进一步感兴趣,请阅读 CQRS 和事件溯源模式。

于 2018-05-02T22:10:00.547 回答