我们已经成功使用 Rabbit 大约一年了。最近升级到 v2.6.1,因为我们想使用带有复制消息队列的集群。
我的测试遇到了一个令人费解的行为,对我来说闻起来像兔子虫。揭示这一点的测试正在使用一个双节点集群。两个节点都运行 v2.6.1。两个节点都有磁盘。两个节点都在 Mac OS 上运行,尽管我怀疑这是否相关。
我还在运行测试的节点上运行 Alice。该测试使用它以编程方式在其中一个节点上执行 stop_app,因为该测试试图验证如果集群主节点失败,并且从节点被提升以取代它,我们不会丢失消息。
因此,测试有一个小线程池,它被赋予周期性的任务 1) 发布消息,以及 2) 切换 Rabbit 主节点的状态(如果运行则停止;如果停止则启动)。其他线程正在使用来自队列的消息。
我正在使用发布者确认,并且我也在确认消费者中的消息(对 channel.basicConsume() 使用 autoAck=false)。
当主节点停止时,我看到生产者和消费者都捕获了 ShutdownSignalException。他们通过尝试重新连接到集群来处理这个问题。这工作正常。重新连接后,他们继续他们的业务。
有时,我看到消费者已成功从代理获取消息,并在收到 ShutdownSignalException 时调用 channel.basicAck()。
稍后,当消费者重新连接时,它再次拉下相同的消息。(消息体用 UUID 标记,所以我知道它是同一个。)这一次,当消费者尝试 basicAck() 消息时,它再次得到 ShutdownSignalException,但是这个包含以下文本:“回复文本 = PRECONDITION_FAILED - 未知交付标签 7"。
事实上,这与在主服务器宕机和消费者重新连接之前代理提供给消费者的交付标签相同。
谷歌搜索表明此事件意味着消费者正在尝试多次确认同一消息。
但是,怎么会这样呢?如果第一次确认成功,则消息应该已从代理的队列中删除,并且消费者不应再次看到相同的消息。
然而,如果第一次确认没有成功,那么消费者不应该因为试图重新确认消息而受到指责。
有人见过这个吗?对我来说,这闻起来像是 Rabbit 复制队列中的一个错误,但我对 Rabbit 还是陌生的,因此我愿意相信从我尚未了解的集群代理中消费的微妙之处!
谢谢,--史蒂夫