MQ - 如何保证在非交易的轻量级环境中传递消息?

时间:2017-10-26 07:14:35

标签: transactions zeromq microservices mq 2phase-commit

如何保证在非交易的轻量级环境中传递消息?

例如:

  • 正常情况:写入数据库,提交,向ZeroMQ发送消息| Redis | OtherMQ ,消费者拉取消息继续处理......
  • 0,05%情况:写入数据库,提交,应用程序死亡!,没有消息发送,没有消费者提取消息,处理不完整。

在这种情况下如何不丢失消息(避免不发送消息)?

修改:邮件必须只发送一次。

2 个答案:

答案 0 :(得分:2)

在这种情况下,您有2个共享资源(数据库和队列),并且您希望它们一起进行交易。如果消息发送到队列,您希望数据库提交。如果未成功发送数据库,您希望数据库不提交,反之亦然。这只是像2PC这样的全局事务机制。然而,实现全局事务机制并不容易,而且成本也很高。

我建议你在生产者方面实施至少一种策略,在消费者方面实现幂等性以提供一致性。

您应该在生产者端的数据库上创建一个消息表,并在发送到队列之前将消息保留到此表。然后使用预定的线程(这里可能有多个线程来增加吞吐量,但是如果您的消息需要按照它们生成的顺序消耗,请小心)或者您可以将它们发送到队列并将其标记为已发送以确保已发送的邮件将不会再次发送。即使您这样做,也可能会出现一些情况,即您的邮件被多次发送(例如,您在将邮件标记为已发送之前将邮件发送到队列并且您的应用程序崩溃)。但这不是问题,因为我们已经想要在生产者方面实施至少一次策略,这意味着我们希望将消息至少发送到队列一次。

为了防止消费者使用在生产者方面多次生成的相同消息,您应该实现幂等消费者。简单地说,您可以将消费消息的ID保存到消费者端的数据库表中,在处理来自队列的消息之前,您可以检查它是否已被消耗。如果它已被消耗,您应该忽略它并获取下一条消息。

当然,还有其他选择可以在微服务环境中提供一致性。您可以在这个伟大的博客上找到其他解决方案 - https://www.nginx.com/blog/event-driven-data-management-microservices/。我在上面解释的解决方案也存在于此博客中。您可以在使用本地交易发布事件部分找到它。

答案 1 :(得分:0)

这可能是一个简单的方法。

我们假设你有交易:

  1. 将数据写入DB
  2. 通过ZMQ发送消息
  3. 写入DB,表示发送正常
  4. 因此,假设您在步骤2或3中时应用程序崩溃。如果是这样,您不知道上一条消息是否确实收到了客户队列,并且您必须在重新启动所有消息后重新发送而不进行最后一次确认(步骤3 )。

    问题出在消费者方面,因为它可能会收到两次消息。要解决此问题,您可以为每条消息发送一个始终在增加的事务ID。消费者必须注意到最后一条消息的事务ID。当传入消息的事务ID不高于最后一条消息的事务ID时,可以忽略该消息。

    现在的问题是,您是否可以修改消息结构以及可以使用的事务ID。