如何防止Google Cloud PubSub中出现重复的味精?
说,我有一个代码可以处理所订阅的味精。
说,我有2个具有相同服务且具有此代码的节点。
一旦收到消息但尚未确认,另一节点将收到相同的消息。这就是我们有两个重复的消息的问题所在。
void messageReceiver(PubsubMessage pubsubMessage, AckReplyConsumer ackReply) {
submitHandler.handle(toMessage(pubsubMessage))
.doOnSuccess((response) -> {
log.info("Acknowledging the successfully processed message id: {}, response {}", pubsubMessage.getMessageId(), response);
ackReply.ack(); // <---- acknowledged
})
.doOnError((e) -> {
log.error("Not acknowledging due to an exception", e);
ackReply.nack();
})
.doOnTerminate(span::finish)
.subscribe();
}
对此有什么解决方案?这是正常行为吗?
答案 0 :(得分:2)
Google Cloud Pub / Sub使用“至少一次”交付。来自the docs:
通常,Cloud Pub / Sub按发布的顺序一次发送每条消息。但是,有时邮件可能会乱序发送或不止一次发送。通常,要容纳多于一次的传递,则要求您的订阅者在处理消息时必须idempotent。
这意味着它保证将传递消息1:N次,因此,如果您不通过其他方式对其进行重复数据删除的方式进行管道传输,则有可能多次获得该消息。您无法定义任何设置来保证一次交货。该文档确实引用了您可以使用Cloud Dataflow的PubSubIO
获得所需的行为,但是that solution appears to be deprecated:
您可以使用Cloud Dataflow
PubsubIO
对Cloud Pub / Sub消息流进行一次处理。 PubsubIO对自定义消息标识符或由Cloud Pub / Sub分配的消息标识符重复删除消息。
说了这么多,我从未实际上见过Google Cloud Pub / Sub发送两次消息。您确定这确实是您遇到的问题,还是因为您未在“确认截止日期”内确认消息而重新发布了消息(如上所述,默认值为10秒)。如果您不同意,它将重新发出。来自the docs (重点是我):
为单个主题创建了一个订阅。它具有几个可以在创建时设置或以后更新的属性,包括:
- acknowledgment deadline:如果您的代码未在截止日期之前确认该消息,则会再次发送该消息。。默认值为10秒。您可以指定的最大自定义截止期限为600秒(10分钟)。
如果是这种情况,只需在截止日期之前确认您的消息,您就不会经常看到这些重复项。
答案 1 :(得分:0)
您可以使用Memorystore中的Redis来重复删除邮件。您的发布者应在将其发布到PubSub之前将跟踪iD添加到消息正文中。另一方面,客户端(订户)应检查跟踪ID是否在缓存中-跳过该消息。如果没有这样的消息,请处理该消息,并在7-8天的到期时间(PubSub截止日期为7天)中添加跟踪ID到缓存。您可以通过这种简单的方式授予收到的正确消息。
答案 2 :(得分:0)
给定主题中的所有消息均具有唯一的messageID
字段:
此消息的ID,由服务器在发布消息时分配。 保证在主题内具有唯一性。该值可由订阅者读取,该订阅者通过subscriptions.pull调用或推送传递接收PubsubMessage。发布者不得在topic.publish调用中填充它。
您可以使用它来重复删除传入的消息。无需手动分配ID。
在分布式系统中(例如,给定订阅的使用者的多个实例),它要难一些。您将需要一个全局同步机制,最简单的方法是设置数据库(例如Redis)并使用它来保留已处理的消息ID。
您应该查看Replaying and discarding messages,其中介绍了如何配置邮件保留。
订阅有两个属性:
retain_acked_messages
-保留确认消息,message_retention_duration
-保留邮件多长时间。如果您不打算将订阅倒带到过去的某个时间点,例如如果您不打算重新处理邮件或存在迫使您重置订阅的错误,则可以设置 retain_acked_messages=false
和 message_retention_duration='3600s'
。这将使您仅保留最后一小时的消息ID。
请记住,PubSub消息也有publish_time
,因此您无需将其添加到消息的数据中。可以与message_id
一起使用。这两个都是由PubSub服务器在收到消息时设置的。