【问题标题】:Best practice for subscribe and publish architecture for chat-like app聊天类应用的订阅和发布架构的最佳实践
【发布时间】:2021-07-15 15:48:22
【问题描述】:

我想知道在订阅更改并将其发布给用户方面存在哪些最佳做法。这是一个相当广泛且措辞模糊的问题。因此,请允许我用一个例子来详细说明这一点。

想象一下以下(简化的)类似聊天的应用程序:

  • 用户打开应用并看到主屏幕。
  • 在此主屏幕上获取并显示聊天组列表。
  • 每个聊天组都有一个用户(成员)列表。
  • 用户可以查看此成员列表。
  • 每个用户/成员至少有一个可用的名字。
  • 用户可以在设置中更改其名称。
  • 现在是重要的部分:更改此名称后,查看成员列表的每个用户都应该实时看到名称更改。

我的问题是关于最后一点。

让我们创建一些非常幼稚的伪代码来模拟这样的事情。

客户至少应该订阅一些东西。所以我们可以这样写:

subscribeToEvent("userChanged")

后端应该使用正确的数据发布到此事件。所以是这样的:

publishDataForEvent("userChanged", { userId: "9", name: "newname" } )

这个代码当然有问题。订阅用户现在获取每个用户的所有事件。相反,它应该只接收它感兴趣的用户的事件(即它当前正在查看的成员列表)。

现在这是我想进一步了解的问题。我可以想到几个解决方案:

方法一 客户端订阅该事件,并与它一起发送他当前正在查看的组的 ID。比如这样:

subscribeToEvent("userChanged", { groupId: "abc" })

因此,在后端,当用户更改其名称时,应该会发生以下情况:

  1. 获取用户的所有组 ID
  2. 使用这些组 ID 发送事件

类似这样的:

publishDataForEvent("userChanged", { userId: "9", name: "newname" }, { groupIds: ["abc", "def" })

由于用户订阅了一个 id 为“abc”的组,并且后端发布到多个组,包括“abc”,因此用户将收到该事件。

此方法的一个缺点是后端应始终获取正在更改的用户的所有组 ID。

方法二

与方法 1 相同。但我们将使用 userIds,而不是 groupIds。

subscribeToEvent("userChanged", { myUserId: "1" })

因此,在后端,当用户更改其名称时,应该会发生以下情况:

  1. 获取与用户相关的所有用户 ID(例如,friendIds 基于与他共享群组的用户)
  2. 使用friendIds 发送事件

类似这样的:

publishDataForEvent("userChanged", { userId: "xyz", name: "newname" }, { friendIds: ["1", "2" })

这样做的一个优点是订阅可以更容易地重用。因此,用户不需要为他打开的每个组启动单独的订阅,因为他使用自己的 userId 而不是 groupId

此方法的缺点是它(与方法 1 类似,但可能更糟)可能需要大量 id 才能将事件发布到。

方法3

这个有点不同。

在此方法中,客户端订阅多个 id。

一个例子:

在客户端,应用程序收集与当前用户相关的所有用户。例如,这可以通过收集当前查看组的所有用户 ID 来完成。

subscribeToEvent("userChanged", { friendIds: ["9", "10"] })

在后端,发布方法可以非常简单,如下所示:

publishDataForEvent("userChanged", { userId: "9", name: "newname" }, { userId: "9" } )

由于客户端订阅了userId为“9”的用户,在多个用户中,客户端会收到此事件。

这种方法的优点是后端发布方法可以相当简单。

这样做的缺点是客户端需要相当多的逻辑来订阅正确的用户。


我希望这些例子能更清楚地说明问题。我觉得我在这里错过了一些东西。像,主要的聊天应用程序公司,不能以这些方式之一来做吗?我很想听听您对此的看法。


顺便说一句,我使用 graphql 作为后端。但我认为这个问题足够笼统,不能让它发挥作用。

【问题讨论】:

    标签: websocket publish-subscribe


    【解决方案1】:
    • 用户可以在设置中更改其名称
    • 现在是重要的部分:更改此名称后,查看成员列表的每个用户都应实时看到名称更改。

    我假设用户可以通过 FORM 更改他的名字。该表单的内容将通过 HTTP-Reuqest 发送到 backand 脚本,该脚本将在数据库中进行更改,例如

    update <table> set field=? where userid=? 
    

    首选

    这将是后端脚本连接到您的 Web 套接字服务器并发送类似消息的位置。

    { opcode:'broadcast', task:'namechange', newname='otto' ,userid='47111' }
    

    服务器将广播给所有连接的客户端

    {task:'namechange', newname='otto' ,userid='4711' }
    

    所有与 userid='4711' 有关系的客户现在都可以采取行动了。

    备选方案 1

    如果您无法将后端脚本连接到 Web 套接字服务器,客户端可能会发送 { opcode:'broadcast', task:'namechange', newname='otto' ,userid='47111' } 就在 FORM 被传输到后端脚本之前。

    这是不稳定的,因为如果后端出现任何问题,虚假消息已经传递,或者客户端可能在消息发出之前就死了,那么没有人会注意到变化。

    【讨论】:

    • 感谢您的回答。我不是在寻找关于 pubsub 应该如何工作的答案,而是在寻找草图场景的(现实世界)最佳实践。无论如何,感谢您的宝贵时间。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-19
    • 2013-05-07
    • 2022-01-16
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多