Cloud Pub/Sub 在回调中缺少 ack/nack 不会导致重新交付

Posted

技术标签:

【中文标题】Cloud Pub/Sub 在回调中缺少 ack/nack 不会导致重新交付【英文标题】:Cloud Pub/Sub missing ack/nack in callback not causing redelivery 【发布时间】:2019-11-29 01:46:18 【问题描述】:

我正在尝试确保 Cloud Pub/Sub 在未发送 ack/nack 时重新发送我的消息。即使我等待超过 10 分钟,它似乎也没有这样做,这应该是 Acknowledgement Deadline 的最长时间。

我在这里使用示例作为起点: https://cloud.google.com/pubsub/docs/quickstart-py-mac

基本上,我在回调函数中注释了确认消息的行。我使用了两个终端,一个用于发布消息,一个用于作为订阅者接收消息。由于没有发送确认,我希望 Cloud Pub/Sub 尝试在确认截止日期内的某个时间将消息重新传递给订阅者,但事实并非如此。

这里的文档

https://godoc.org/cloud.google.com/go/pubsub#hdr-Deadlines

说“客户会定期延长 ACK 截止日期......最多 10 分钟”,所以我等了 10 分钟,以防 ack 截止日期被延长到那个最大值,但我仍然没有收到重新传递的消息。

这是我使用的编辑后的回调方法。这是我对示例代码所做的唯一更改。

def callback(message):
        print('Received message  of message ID '.format(
            message, message.message_id))
        # Acknowledge the message. Unack'ed messages will be redelivered.
        # message.ack()
        print('Acknowledged message of message ID \n'.format(
            message.message_id))

如果我终止订阅者 (sub.py) 并重新启动它,则消息会重新传递。难道我做错了什么?此外,当我发送 Nack 而不是根本不发送任何内容时,消息会很快重新传递。

编辑:

好像有人问过类似的问题

https://github.com/googleapis/google-cloud-python/issues/5005

https://github.com/googleapis/google-cloud-python/issues/5044

我想确认的事情:

    订阅中设置的确认截止日期并不总是使用的值。它会在 Pub/Sub 认为必要时进行扩展。

    10 分钟的最大确认截止日期实际上并不是重新传递消息之前可以经过的最长时间

    此最长时间由 flow_control.max_lease_duration 变量确定(默认为 2 小时)

【问题讨论】:

将此添加到代码底部return abort(500)。消息是否重新传递? @JohnHanley 将return abort(500) 添加到我的回调方法的末尾会导致此错误:'No handlers could be found for logger "google.cloud.pubsub_v1.subscriber._protocol.streaming_pull_manager"',然后立即, 大约每半秒连续重新传递消息。我担心的问题是,如果由于某种原因回调停止或出错并且 ack/nack 从未发送(或者在这种情况下,中止) 我不确定这是否有帮助,但我运行了订阅者几个小时,在遇到此错误后,“RetryError: Deadline of 600.0s exceeded while calling ,最后一个例外:503 未能连接到所有地址”,消息开始每 10-12 秒重新传递一次。也许这导致确认截止日期被重置为默认值? 【参考方案1】:

ackDeadline 是在没有 ack、nack 或 modAckDeadline 的情况下,消息对订阅者的未处理的最长时间。一旦这段时间过去,该消息将成为重新传递的候选者,尽管重新传递可能不会立即进行。此字段的最大值为十分钟。

Cloud Pub/Sub 客户端库在收到消息后,会自动发送消息的 modAckDeadline 请求,直到它被确认、确认或 flow_control.max_lease_duration 周期过去。本质上,它延长了确认期限。目标是让客户端库跟踪确认截止日期并根据需要扩展消息本身,这样用户就不必这样做。

这就是您看到客户端库行为与订阅上配置的ackDeadline 之间存在差异的原因。使用客户端库时,您应该将 max_lease_duration 设置为您希望消息未发送给订阅者的最长时间。

【讨论】:

感谢您的回答!我仍然感到困惑的一件事是,为什么当我运行从不 ack 或 nack 的订户时,max_lease_duration 并不总是被击中。重新发送间隔似乎是随机的,10 秒到 2 小时之间的任何持续时间 这些值都不是保证在该时间范围内不会重新传递消息。由于网络或服务器故障,消息可能会在max_lease_duration 之前重新传递。

以上是关于Cloud Pub/Sub 在回调中缺少 ack/nack 不会导致重新交付的主要内容,如果未能解决你的问题,请参考以下文章

Google Pub/Sub + Cloud Run 生成多个容器

Google Cloud Pub/Sub,使用 HTTP PUSH 请求发布

javascript Google Cloud函数用于在pub / sub和pub / sub到Big查询中发布数据

如何在 Google Cloud Function 上的 Spring Cloud 函数中获取 Pub/Sub 事件的元数据

为了在 Google Cloud 中启用 Cloud Pub/Sub 作为通知通道,必须做些啥

Firebase Cloud Functions 如何确认 Cloud pub/sub