首页 文章

如何确保只有一个消费者实际消费已发布的消息?

提问于
浏览
0

我使用Rabbitmq和微服务架构 . 我使用主题和直接交换我的许多用例,它工作正常 . 但是我有一个用例,我必须从数据库中删除一条记录 . 当我删除记录时,需要调用其他几个服务并维护/删除引用的记录 . 我可以通过直接交换简单地调用那些服务来实现这一点,但我读到它是编排首选而不是编排 . 这意味着我应该实现发布/订阅模式(rabbitmq中的扇出) . 我的问题是,如果我在分布式系统中使用发布/订阅模式,如何确保服务中只有一个实例使用已发布的消息?

2 回答

  • 2

    您的问题与发布 - 订阅的处理不同,因为它与基本的消息处理有关 . 根本问题在于您是否可以保证操作只执行一次 . 简短的回答是,您可能希望使用直接交换,以便消息进入一个队列并由一个(可能很多)消费者处理 .

    答案很长,“完全一次”是无法保证的,因此您需要将这部分设计成一部分 .

    Background

    最佳做法是将消息处理作为 idempotent 操作 . 实际上,幂等性是几乎所有外部接口的关键设计假设(我认为它在内部接口中同样重要) .

    此外,您应该意识到无法保证“一次性”交付 . 在数学上,没有这样的保证 . 相反,你可以拥有两件事之一(互相排斥):

    • 最多一次交货(0 <n <= 1)

    • 至少一次交货(1 <= n)

    来自RabbitMQ文档:

    确认的使用保证至少一次交付 . 如果没有确认,则在发布和使用操作期间可能会丢失邮件,并且只保证最多一次传递 .

    发布和使用消息时会发生一些事情 . 由于消息处理系统的异步特性,特别是AMQP协议,没有办法保证一次处理,同时仍然可以从消息系统中获得所需的性能(实质上,试图确保一次性强制)通过重复数据删除点的连续过程完成所有事情 .

    Design Implications

    鉴于上述情况,您的设计必须依赖"at least once"交付 . 对于删除操作,这涉及将该操作的定义重写为断言而不是过程(例如“删除此" becomes "确保不存在 . ”) . 不同之处在于您描述了最终状态而不是过程 .

  • 1

    我应该为每个服务都有一个单独的队列,该实例应该通知有关db记录删除的通知 . 交换机将消息的副本放在所有队列中 . 服务实例竞争访问专用队列(只有一个获取消息) .

相关问题