为什么我们的 GCP Cloud Function 会从其 PubSub 订阅中收到如此多的重复项?

Wil*_*rin 5 google-cloud-pubsub google-cloud-functions

简而言之

有一个 Google Cloud PubSub 主题,我们向其发布 200 万条微小/小型消息。我们设置了一个云函数来处理通过该主题发送的消息。在检查日志时,我们发现许多此类消息被多次处理。总而言之,我们收到的消息数量为 150-200%(请参见最后的屏幕截图)。

问题是:这是为什么?我们如何正确配置事物以减少重复?

附加信息

  • 在发布 2M 条消息并且执行此操作的脚本完成后,订阅中的消息数似乎是正确的。我认为我们可以因此排除“发布端”重复,在本文1中标记为和。2
  • 订阅的配置由 Cloud Function 管理,我们无法编辑。所以我猜这是所有云功能的默认/强制配置。请参阅下面的屏幕截图。
  • 在“订阅者端”重复引用的最常见原因是函数需要比确认截止时间更长的时间来确认消息(例如此处)。订阅的确认截止时间设置为 600 秒,但函数运行时间最多可达几秒。
  • 我们也根本不进行批处理,这消除了经常引用的另一个原因(例如在这个问题本文中)。
  • 该函数仅限于 90 个实例。

更新 15.03.22

所以我想绝对确定这是“真正的”重复,我的意思是它是 PubSub 多次传递消息/事件,而不是我们在某个地方笨拙地引入的重复。因此,我修改了函数代码,根据外部消息 ID 形成数据存储区密钥,并context.messageId使用计数器将其写入数据存储区。如果密钥已经存在,则计数器会递增。之后我立即记录该实体。以下是 458,940 次处决的统计数据:

|-------------------|-------------------|
|      Counter      |       Logs        |
|-------------------|-------------------|
|         1         |       208,733     |
|         2         |       101,040     |
|         3         |       62,965      |
|         4         |       37,156      |
|         5         |       20,583      |
|         >5        |       28,463      |
|         >15       |       20          |
|         >20       |       0           |
|-------------------|-------------------|
Run Code Online (Sandbox Code Playgroud)

我唯一的(糟糕的)线索

我现在唯一的理论是,重复是由于底层基础设施由于实例限制而响应 429。请参阅以下屏幕截图。

在此输入图像描述

我们不再真正注意到这一点,因为我们只是通过过滤 for 来在日志控制台中过滤出相应的日志消息log_name,因为基础设施抛出大量警告和错误似乎是预期的行为。这就是为什么我也怀疑这是重复的原因。另一方面,在这些情况下,基础设施看起来确实可以发送 NACK。

尽管感觉预期的行为是原始消息的传递失败并返回 429(但不会显示在我们的日志中),然后重新传递,可能会重复。这不是我们所观察到的,我们的日志确实显示重复的执行。

所以我不确定这是否是一个有希望的线索,但这就是我现在所得到的。

其他资源

我觉得我们所观察到的内容听起来与这个问题此处的文档中描述的内容相似,但是这是关于“StreamingPull”订阅,而 GCF 托管订阅似乎是(特殊?)“推送”订阅。一开始我很兴奋,因为听起来很相似,但似乎并不适用。

截图

显示主题之间的消息重复的屏幕截图:

在此输入图像描述

订阅配置(由 GCF 管理):

在此输入图像描述

Jos*_*iza 1

发生429 \xe2\x80\x99s 错误的原因是请求过多或实例流量过多。另外,您的最大实例数为 90,建议默认值为 3000

\n

此外,如果您不想设置任何限制,您可以删除最大实例数或将其设置为 0。另一方面,您可以添加更高的最大实例数(从 90 到 180),最后再稍高一些,以解决 429\xe2\x80\x99s 错误的问题。

\n

其他可能导致订阅中出现重复行为的因素包括:

\n
    \n
  • 订阅者\xe2\x80\x99s 队列中的消息未在截止期限内得到处理和确认;

    \n
  • \n
  • 客户端库继续(自动)延长截止时间\n希望最终能够处理这些消息;

    \n
  • \n
  • 在某些时候,在多次延长截止日期之后,客户端库\ng放弃了,因此这些消息被丢弃并重新传递;

    \n
  • \n
  • Pub/Sub 中的消息是批量投递的,因此不仅过期的消息会被重新投递,属于这些批次的消息也会被重新投递;

    \n
  • \n
  • 订阅者的队列将充满重复项,这会减慢\n积压的消耗;

    \n
  • \n
  • 由于当前的重复项也会过期并生成新的重复项,因此问题变得越来越严重。

    \n
  • \n
\n