【问题标题】:How to ensure message idempotency with multiple competing consumers?如何确保消息与多个竞争消费者的幂等性?
【发布时间】:2010-12-12 17:49:30
【问题描述】:

我有多个分布式竞争消费者,每个消费者都从同一个(事务性)队列中提取消息。我想将每个消费者实现为Idempotent Receiver,因此即使重复到达,我也不会多次处理同一消息(跨所有消费者)。如何在多个消费者中实现这一点?

我的第一个想法是在将它们放入队列之前以某种方式为每条消息生成一个连续的序列号,然后使用共享数据库表来协调消费者之间的工作。 IE。 consumer#1 处理 msg#1,然后将一行写入 DB 表,说明“msg#1 已处理”(希望它在数据库中以确保持久性)。当消费者准备好处理消息时,它会查看队列中的下一个可用消息,查阅共享数据库表并确定这是否是按顺序排列的下一个消息。如果是这样,它会将其从队列中拉出。如果不是,它会忽略它。

这样,我只需要存储最后处理的消息(因为所有消息都有一个连续的序列号),我不需要使用缓冲区来存储通过协商的“窗口”接收到的所有消息的 ID大小,并且消息总是被串行处理(这是我想要的这个场景)。

只是好奇是否有更好的方法?我担心每当我需要处理消息时查询数据库的成本。

如果答案是“它取决于框架”,那么我想到了 MSMQ

【问题讨论】:

    标签: messaging idempotent


    【解决方案1】:

    幂等接收者的要点是,如果消息被处理多次,则无关紧要。因此,幂等接收者不需要以某种方式检测消息是否重复,他们可以像往常一样简单地处理它......

    所以要么你的接收者不是幂等的,要么你在不必要地担心......

    【讨论】:

    • 如果我的 API / 消息处理逻辑被设计成幂等的,那么是的,我不需要担心收到重复的消息。我的情况并非如此。我需要过滤掉重复的消息,而不仅仅是针对消费者的一个实例,而是跨多个实例。
    • 但是如果我必须保证幂等性的唯一方法是避免第二次发生副作用呢?
    • 幂等是一个实现细节,它不是魔法。您可以通过确保您的“消息”是幂等的来做到这一点,例如将值 X 设置为 5,或者通过记录消息已被处理的事实来做到这一点。完成后者的最佳方法是让每条消息都包含一个 GUID 或其他唯一 ID,并将其记录在与您更改持久性存储中的状态相同的事务中。对于每条消息,您可以检查 GUID 是否已经被处理,知道它在与状态更改相同的事务中。
    • 这毫无意义。这个答案意味着接收到消息时执行的每一段代码都必须是幂等的。这太超现实了。
    • 这个答案应该是正确的。例如。收到的消息是“SendWelcomeEmail” - 您必须跟踪该消息是否已被处理,或者以其他方式标记它。
    【解决方案2】:

    我通过确保每条消息都有一个 GUID 或其他唯一标识符,然后将其记录在与您更改持久性存储中的状态相同的事务中,从而实现了幂等消息。

    您现在可以检查每条消息的唯一 ID 是否存在于您的持久性存储中。

    如果唯一 id 存在,您就知道它之前已被处理过,并且状态更改保留在同一个事务中。

    如果唯一id不存在,就知道它从未被处理过。

    如果两个消费者处理相同的消息,因为您存储已处理的唯一 ID 的表具有唯一约束,当两个消费者都提交事务时,其中一个必须失败并回滚所有更改,而另一个会成功。

    【讨论】:

      【解决方案3】:

      安德鲁-

      另一个选项是查看您的队列如何处理消息。有队列在消息被消费者拾取后删除消息。这是队列的典型行为,不难找到具有这种功能的队列。这应该为您提供一个简单的解决方案,而不是为每个消费者构建一种方法来确保他们不会收到已经被另一个消费者处理过的消息。

      最好, 亨利

      【讨论】:

      • 这仍然没有解决消息已被“删除”、消息已被处理并且状态持久保存到数据库但正如进程确认消息失败的故障模式,这意味着消息将被放回队列并再次重新处理。
      • 通常一条消息不会被删除,只是在队列框架确认它已被成功处理之前无法被拾取。如果队列从未收到 ACK,则会遇到处理超时,然后假设它是这样配置的,消息将被放回队列中。您的用例是众所周知且已得到很好解决的情况。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-29
      • 2010-12-05
      • 2019-07-16
      • 2020-06-23
      • 1970-01-01
      • 1970-01-01
      • 2018-06-03
      相关资源
      最近更新 更多