Google Cloud Pub/Sub 如何避免时钟偏差

Posted

技术标签:

【中文标题】Google Cloud Pub/Sub 如何避免时钟偏差【英文标题】:How is Google Cloud Pub/Sub avoiding clock skew 【发布时间】:2019-08-20 09:51:59 【问题描述】:

我正在研究从谷歌云发布/订阅订购消息列表的方法。 The documentation 说:

有一种方法可以从它当前收到的所有消息中确定是否有它尚未收到的消息需要首先处理。

...可以通过使用 Cloud Monitoring 跟踪 pubsub.googleapis.com/subscription/oldest_unacked_message_age 指标来实现。订阅者会临时将所有消息放在某个持久存储中并确认消息。它会定期检查最旧的未确认消息年龄,并检查存储中消息的发布时间戳。保证在最旧的未确认消息之前发布的所有消息都已收到,因此可以从持久存储中删除这些消息并按顺序处理。

我在本地对其进行了测试,这种方法似乎运行良好。

不过,我对此有一点不满,而且这不是我自己可以轻易测试的。

此解决方案依赖于服务器端分配(由 google)publish_time 属性。 Google 如何避免时钟歪斜的问题?

如果我的生产者发布消息 A,然后立即发布 B,我如何确定 A.publish_time < B.publish_time 是真的?特别是考虑到相同的文档页面提到了解决方案架构中的内部负载平衡器。 Google Pub/Sub 是否使用原子钟在第一台看到消息并用当前时间丰富这些消息的机器上同步时间?

在推荐的解决方案中有一个隐含的假设,即所有服务器上的时钟都是同步的。但是文档从未解释这是否属实或如何实现,所以我对解决方案感到有点不安。它可以在非常高的负载下工作吗?

请注意,我只对相互发布的已确认消息的相对顺序感兴趣。如果同时发布两条消息,我不关心它们之间的顺序。可以是A, BB, A。我只想确保如果 B 在 A 发布之后发布,那么我可以在检索时按该顺序对它们进行排序。

上述解决方案只是“尽力而为”还是对这种行为有实际保证?

【问题讨论】:

【参考方案1】:

有序的消息传递有两个方面:在发布端建立消息的顺序,在订阅端建立处理消息的顺序。您参考的文档主要与后者有关,尤其是在使用oldest_unacked_message_age 时。使用此方法时,可以知道如果消息 A 的发布时间戳小于消息 B 的发布时间戳,那么订阅者将始终在处理消息 B 之前处理消息 A。本质上,一旦建立订单(通过发布时间戳),它将是一致的。如果 Cloud Pub/Sub 服务本身可以建立消息的顺序,则此方法有效。

发布时间戳不会跨服务器同步,因此如果发布者需要建立订单,发布者需要提供时间戳(或序列号)作为用于排序的属性在订阅者中(并在发布者之间同步)。订阅者将按此用户提供的时间戳而不是发布时间戳对消息进行排序。 oldest_unacked_message_age 将不再准确,因为它与发布时间戳相关联。一种可能更保守,只考虑比oldest_unacked_message_age 更早的消息排序减去一些增量来解释这种差异。

【讨论】:

【参考方案2】:

Google Cloud Pub-sub 不保证消费者在生产时收到的事件顺序。其背后的原因是 Google Cloud Pub-sub 也在节点集群上运行。有可能事件 B 可以在事件 A 之前到达消费者。为了确保排序,您必须对生产者和消费者进行更改以识别事件的顺序。 Here 是文档中的部分。

【讨论】:

以上是关于Google Cloud Pub/Sub 如何避免时钟偏差的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Google Cloud Pub/Sub 进行 Junit 测试

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

如何将 Google Cloud Platform Pub/Sub 消息推送到 C# 桌面应用程序

如何从 Firebase Cloud Function 在 Google Pub/Sub 中发布消息?

如何在将消息发布到 Google Cloud Pub/Sub 时找出未找到的资源?

Google Cloud 上使用 Pub/Sub 的主/从模式