如何在确保每个实体的FIFO的同时并行处理消息?

时间:2011-04-15 17:50:33

标签: concurrency message-queue activemq rabbitmq hornetq

假设您的系统中有一个实体,比如说“人”,并且您希望处理修改各种Person实体的事件。重要的是:

  • 同一人的事件按FIFO顺序处理
  • 多人事件流由不同的线程/进程并行处理

我们有一个实现可以使用共享数据库和锁来解决这个问题。线程竞争获取Person的锁定,然后在获取锁定后按顺序处理事件。我们希望转移到消息队列以避免轮询和锁定,我们认为这会减少数据库的负载并简化消费者代码的实现。

我已经对ActiveMQ,RabbitMQ和HornetQ做了一些研究,但我没有看到一种明显的方法来实现它。

ActiveMQ支持消费者订阅通配符,但我没有看到将每个队列的并发限制为1的方法。如果我能做到这一点,那么解决方案就会很简单:

  • 以某种方式告诉代理允许以:/ queue / person开头的所有队列的并发性为1。
  • Publisher使用队列名称中的人员ID将事件写入队列。例如:/queue/person.20
  • 消费者使用通配符订阅队列:/queue/person.>
  • 每个消费者都会收到不同人员队列的消息。如果所有人都在使用,一些消费者可能会闲置,这没关系
  • 在处理消息之后,消费者发送一个ACK,告诉代理它已完成消息,并允许将该Person队列的另一条消息发送给另一个消费者(可能是同一个消息)

ActiveMQ接近:您可以执行通配符订阅并启用“独占消费者”,但这种组合会导致单个消费者接收发送到所有匹配队列的所有消息,从而将所有人的并发性降低到1。我觉得我错过了一些明显的东西。

问题:

  • 有没有办法在任何主要的消息队列实现中实现上述方法?我们对选择相当开放。唯一的要求是它在Linux上运行。
  • 有没有不同的方法来解决我不考虑的一般问题?

谢谢!

3 个答案:

答案 0 :(得分:3)

看起来我正在寻找JMSXGroupID。来自ActiveMQ文档:

http://activemq.apache.org/message-groups.html

他们的股票价格示例用例正是我所追求的。我唯一担心的是如果单个消费者死亡会发生什么。希望经纪人能够检测到并选择另一个与该组ID相关联的消费者。

答案 1 :(得分:1)

解决这个问题的一般方法(如果我的问题是正确的)是为Person引入一些独特的属性(比如Person的数据库级id),并使用该属性的哈希作为FIFO队列的索引来放置人。
由于该属性的哈希值很大(您无法承受2 ^ 32个队列/线程),因此只使用该哈希值的N个最低有效位。 每个FIFO队列都应该有专门的工作人员来处理它 - 瞧,您的要求得到满足!

这种方法有一个缺点 - 您的人员必须具有良好分布的ID,以使所有队列的负载或多或少相等。如果您无法保证这一点,请考虑使用循环队列,并跟踪正在处理的人员,以确保为同一个人进行顺序处理。

答案 2 :(得分:0)

如果您已经有一个允许共享锁的系统,为什么不为每个队列锁定消费者在从队列中读取之前必须获取的那个?