谷歌 PubSub 存在拉式订阅者设计缺陷?

Posted

技术标签:

【中文标题】谷歌 PubSub 存在拉式订阅者设计缺陷?【英文标题】:Google PubSub with pull subscriber design flaw? 【发布时间】:2021-06-30 00:37:47 【问题描述】:

我们使用googles steaming pull订阅者设计如下

我们正在做

    将文件从 FE(前端)发送到 BE(后端) 将该文件转换为 ByteArray 并作为消息发布到 pubsub 主题(因此 ByteArray 将作为消息) 向订阅者发送该消息的主题,订阅者再次将 ByteArray 转换为文件 转换后的文件订阅者发送到该工具 工具用文件做一些很酷的事情并将状态通知订阅者 该状态将变为 BE,BE 会更新 DB 并将该状态发送到 FE

现在在我们的订阅者中,当我们收到消息时,我们会立即确认它并删除订阅者的侦听器,这样我们就不会再收到消息了 当该工具完成这些工作时,它会向订阅者发送状态(我们在订阅者上运行快速服务器)和

after receiving status we are re-creating listener of subscriber to receive message

注意

该工具可能需要 1 小时或更长时间才能完成工作 我们正在使用排序密钥将消息正确分发到虚拟机

这段代码运行良好,但我的问题是

这是否有任何缺陷(bcz 我们删除了侦听器,然后再次重新创建它或类似的东西) 或任何更好的选择或 GCP 服务最适合此设计 或任何代码改进

编辑: 删除代码示例

【问题讨论】:

一些问题:可以在架构中添加订阅吗?你忘了它(我敢肯定你只有一个,但只是为了确定)。某些工具的所有过程是否需要1H左右?什么限制了这个过程?为什么您不能同时处理多条消息(因此您需要删除侦听器)?您希望并行处理多少个 VM 来处理所有传入的文件? 感谢您的时间和考虑 1. 架构是什么意思? (我给出的代码就是我们所拥有的,没有多余的东西) 2. 没有一些过程可能需要 2 小时,一些可能需要 30m,一些可能需要 10 分钟,也可能需要 10 分钟 3. 该工具使用转换后的文件,因此一次只处理一个文件并在 VM 4 中做事。VM 取决于客户端,一些客户端可以提供 3 个 VM,有些可能提供 1 个 VM,等等。 当我们收到消息订阅者触发该工具时,该工具会获取转换后的文件并执行操作,因此我们可能无法并行运行该工具 Schema 是您放在问题之上的绘图。是否可以加快转换过程?例如,通过添加 CPU?您的进程需要多少内存 (RAM)?最大文件大小是多少? 好的,知道了 1. 我们每个客户/用户有一个订阅,所以一个订阅可能有两个或多个订阅者,或者一个也有(取决于客户他们可以提供多少 VM)2. 是的,现在可能我们有 32 或 16 GB 内存和大量 CPU(我们正在运行 Windows) 3. 最大大小不会超过 2 或 3 MB 大部分文件都在 KB 中 【参考方案1】:

我会说这个设计有几个部分是次优的。首先,在您完成处理之前确认消息意味着您冒着消息丢失的风险。如果您的工具或订阅者在确认消息后但在处理完成之前崩溃了怎么办?这意味着当进程重新启动时,它们将不会再次收到消息。你对来自前端的请求可能永远不会被处理还好吗?如果没有,您将需要在处理完成后确认,或者 - 鉴于您的处理需要很长时间 - 将请求保留到数据库或某些存储,然后确认消息。如果您无论如何都必须将文件保存在其他地方,您可能需要考虑将 Pub/Sub 排除在外,然后将文件写入 GCS 等存储,然后让您的订阅者直接从 GCS 中读取。

其次,在收到每条消息时停止订阅者是一种反模式。您的订阅者应该在每条消息到达时接收并处理它。如果您需要限制并行处理的消息数量,请使用message flow control。

此外,排序密钥并不是真正“将消息正确分发到虚拟机”的方法。订购密钥只是确保有序交付的一种方式。无法保证相同排序键的消息将持续发送到相同的订阅者客户端。事实上,如果您在收到每条消息后关闭订阅者客户端,那么另一个订阅者可能会收到订购键的下一条消息,因为您已经确认了之前的消息。如果您所说的“正确分发消息”的意思是您希望消息按顺序传递,那么这是使用排序键的正确方法。

您说每个客户都有订阅,那么这是否正确取决于您所说的“客户”。如果客户端的意思是“前端用户”,那么我想您也计划为每个用户设置不同的主题。如果是这样,那么您需要记住每个项目 10,000 个主题的限制。如果您的意思是每个 VM 都有自己的订阅,请注意每个 VM 将接收发布到主题的每条消息。如果您只希望一个 VM 接收每条消息,那么您需要在所有 VM 上使用相同的订阅。

通常,还请注意 Cloud Pub/Sub 具有至少一次交付语义。这意味着即使是已确认的消息也可能会被重新传递,因此您确实需要准备好处理重复的消息传递。

【讨论】:

感谢您的宝贵时间 1. 当进程失败时,该 TOOL 向订阅者(运行服务器)发送状态失败,并且该订阅者向 FE 用户/客户端发送状态,请重新发送该文件(所以所有过程将再次重复) 2.我们要分发(负载平衡)消息,以便它们从用户到 VM 3.client 是 FE 的用户,所以为什么我们需要每个客户端主题 bcz 消息将始终是文件,并且每个客户订阅将由过滤器中订阅中的过滤器选项处理,我们将为客户提供 uuid 4.您能否详细说明 ack msg 可以重新传递 如果我们没有像您在第二段中所说的那样停止订阅者,我们将立即收到第二条消息,并且该工具一次只处理一个文件,那么在这种情况下我们应该怎么做?如果我们没有立即确认并在 TOOL 完成任务后执行确认,那么消息的排序行为不正常,您能帮我们解决这个问题吗? 但是如果崩溃发生在message.ack(); 之后呢?谁发送失败状态?如果您使用的是每个客户端的主题,请记住配额。关于重新传递,确认是尽力而为,因此在您无法控制的情况下,确认可能不会被持久化并且可能会重新传递消息。为确保您一次只收到一条消息,请使用流控制并将最大未完成消息设置为 1,但这将要求您在处理完成之前不确认消息。 如果您在未确认时遇到订购问题,您可能会看到重新交付,而您的订阅者可能对这些问题没有弹性。如果您联系 GCP 支持人员并提供您的项目和订阅,GCP 支持人员可以告诉他们发送和重新发送消息的顺序。 哦,我明白了你的意思,但是 1. 工具的配置方式是,当它崩溃时,它会将状态发送到 /listen 路由,请参见上面的代码,这样我们将配置如果错误,然后告诉用户重新发送文件,我们将再次调用main() 再次创建订阅者处理程序 2. 我们在订阅中使用流控制器作为选项,如上所示

以上是关于谷歌 PubSub 存在拉式订阅者设计缺陷?的主要内容,如果未能解决你的问题,请参考以下文章

PubSub 中发布者的存在信息

Google pubsub_v1 订阅者拉“打开的文件太多”

对云功能执行 http PUSH 的 Google Pubsub 订阅者(在同一项目或另一个项目中)

Pubsub.pull 请求无法正常工作 - 去吧

GCP PubSub 主题推送问题

pubsub 订阅者出错:超出最大消息大小