NSQ重新排队一半消息

时间:2018-09-08 18:32:38

标签: go nsq

我有一个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
}

那么,这是正确的方法吗? 他们在这种情况下有什么缺点吗? 再次发布更好吗?

2 个答案:

答案 0 :(得分:1)

某些队列(例如Kafka)支持确认,直到消费者真正确认成功接收到该项目后,才会从队列中删除已出队的项目。

此模型的优势在于,如果消费者在消费后死亡但在确认之前死亡,则该商品将自动重新排队。模型的缺点是,在这种情况下,该项目可能会丢失。

确认模型的风险在于,现在物品可能被双重消耗。消费者尝试使用具有副作用(例如增加计数器或更改数据库)但不承认的消费,因此重试可能不会产生所需的结果。 (请注意,即使您不重新排队数据,也无法保证通过nsq文档进行重试都可以进行重试,因此无论如何您的代码都可能必须对此采取防御措施。)

如果您想更深入地了解这一点,则应该研究“完全一次”与“最多一次”的处理。

通读nsq文档,似乎并不支持确认,因此,如果必须使用nsq,这可能是您的最佳选择。

答案 1 :(得分:1)

与dolan所说的差不多,您可能会遇到几种情况:

  • 主消息心跳/租约超时,并且您再次收到所有ID(来自原始消息)。 NSQ提供"at least once"语义。
  • 任何单个消息的排队都超时,并且永远不会完成(回退到主要IDS)

因为nsq可以(而且大多数def将:p)多次(CreateObjects /应该idempotent)传递消息才能处理这种情况。

另外,重新交付是重要的安全机制, 在所有个人ID或已确认创建或成功重新排队之前,不应该查找原始消息,以确保不会丢失任何数据。


IMO的处理方式看起来非常好,但是IMO最重要的考虑因素是在将收到重复消息 的环境中处理正确性/数据完整性。


另一种选择是批量处理Requeue,以便它尝试生成失败ID的单个输出消息,这可以在任何给定时间减少队列中消息的数量:

考虑一条包含3个ID的消息:

消息ID:[id1,id2,id3]

id1成功创建,而id2和id3失败:

程序可以尝试所有操作,并发出一条ID2,ID3的重新排队消息。

但是也要以此为代价。