我有一个Ids
类型的int64
数组,这是我要发布的Nsq消息。
nsqMsg := st{
Action : "insert",
Ids : Ids
GID : Gids
}
msg, err := json.Marshal(nsqMsg)
if err != nil {
log.Println(err)
return err
}
err = nsqProducer.Publish(TOPIC-NAME, msg)
if err != nil {
log.Println(err)
return err
}
在我的消费者中,我要一个一个地获取每个ID,并从我的数据存储中获取基于我的ID的信息。
因此,在获取数据时,如果我的CreateObject方法返回错误,则可能会出现这种情况,因此我可以通过重新排队味精(产生错误)来处理这种情况,因此可以重试。
for i := 0; i < len(data.Ids); i++ {
Object, err := X.CreateObject(data.Ids[i)
if err != nil {
requeueMsgData = append(requeueMsgData, data.Ids[i])
continue
}
DataList = append(DataList, Object)
}
if len(requeueMsgData) > 0 {
msg, err := json.Marshal(requeueMsgData)
if err != nil {
log.Println(err)
return err
}
message.Body = msg
message.Requeue(60 * time.Second)
log.Println("error while creating Object", err)
return n
}
那么,这是正确的方法吗? 他们在这种情况下有什么缺点吗? 再次发布更好吗?
答案 0 :(得分:1)
某些队列(例如Kafka)支持确认,直到消费者真正确认成功接收到该项目后,才会从队列中删除已出队的项目。
此模型的优势在于,如果消费者在消费后死亡但在确认之前死亡,则该商品将自动重新排队。模型的缺点是,在这种情况下,该项目可能会丢失。
确认模型的风险在于,现在物品可能被双重消耗。消费者尝试使用具有副作用(例如增加计数器或更改数据库)但不承认的消费,因此重试可能不会产生所需的结果。 (请注意,即使您不重新排队数据,也无法保证通过nsq文档进行重试都可以进行重试,因此无论如何您的代码都可能必须对此采取防御措施。)
如果您想更深入地了解这一点,则应该研究“完全一次”与“最多一次”的处理。
通读nsq文档,似乎并不支持确认,因此,如果必须使用nsq,这可能是您的最佳选择。
答案 1 :(得分:1)
与dolan所说的差不多,您可能会遇到几种情况:
因为nsq可以(而且大多数def将:p)多次(CreateObjects
/应该idempotent)传递消息才能处理这种情况。
另外,重新交付是重要的安全机制, 在所有个人ID或已确认创建或成功重新排队之前,不应该查找原始消息,以确保不会丢失任何数据。
IMO的处理方式看起来非常好,但是IMO最重要的考虑因素是在将收到重复消息 的环境中处理正确性/数据完整性。
另一种选择是批量处理Requeue,以便它尝试生成失败ID的单个输出消息,这可以在任何给定时间减少队列中消息的数量:
考虑一条包含3个ID的消息:
消息ID:[id1,id2,id3]
id1成功创建,而id2和id3失败:
程序可以尝试所有操作,并发出一条ID2,ID3的重新排队消息。
但是也要以此为代价。