Pub/Sub 订阅应用的升级策略

Upgrade strategy for Pub/Sub subscription application

我很好奇如何处理 upgrade/reboot 应用程序使用来自 Google Pub/Sub 的消息的情况。

例如,我特别感兴趣的是开发部署在 Kubernetes 运行 多个 pods 中并使用 Google Pub/Sub 形式的消息的 Golang 应用程序。我担心的是如何确保在升级 pod 时没有消息丢失(或处理两次)。

我了解应用程序会从订阅中读取消息,然后必须确认已收到消息。我觉得在确认消息和 pod 关闭升级之间可能存在竞争条件?

我知道使用 Dataflow 作业可以做类似的事情,因为您可以停止流式处理作业并发出信号以耗尽消息。

我假设必须有某种方式来优雅地处理这个问题,或者这真的是 Dataflow 更适合的情况吗?

Kubernetes 使用 SIGTERM,等待 30 秒,然后是 SIGKILL。这为您的应用程序在完全终止之前提供了适当的时间,如果 30 秒默认值不够 (link 1),您可以使用 terminationGracePeriodSeconds: 60 字段进行调整 (link 1).

然后您需要在 Golang 中添加逻辑以接收 SIGTERM 信号 (link 2)。

最后,假设你的队列在这里是 rabbit(但其他队列将具有类似的功能),在收到 SIGTERM 时,你可以编写逻辑 A)停止接收新消息,然后 B)(这是可选的,你可以让他们完成)return 一个 NACK 和 Requeue 信号,用于所有 pod 当前已确认但未完成的消息,将消息放回(link 3 和 4)。

如果您可以避免必须实施 NACK/Requeue,并且只需通过关闭队列侦听器并完成当前保存的剩余消息(假设 30 或 60 秒就足够了)来处理 SIGTERM,那么更简单,推荐。

  1. https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-terminating-with-grace

  2. Golang catch signals

  3. https://www.rabbitmq.com/nack.html

** 编辑 **

对于google云pub/sub,你也可以发一个Nack。

https://pkg.go.dev/cloud.google.com/go/pubsub#Message

"Ack 表示消息处理成功。如果消息确认失败,消息将被重新传递。Nack 表示客户端不会或不能处理消息。Nack 将导致消息被重新传递的速度比如果更快它被允许过期。"