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

Concurrency 如何并行处理消息,同时确保每个实体的FIFO?,concurrency,message-queue,activemq,rabbitmq,hornetq,Concurrency,Message Queue,Activemq,Rabbitmq,Hornetq,假设您的系统中有一个实体,比如说,Person,您希望处理修改各种Person实体的事件。重要的是: 同一个人的事件按FIFO顺序处理 多人事件流可以由不同的线程/进程并行处理 我们有一个使用共享数据库和锁解决这个问题的实现。线程竞争为一个人获取锁,然后在获取锁后按顺序处理事件。我们希望转移到消息队列以避免轮询和锁定,我们认为这将减少数据库上的负载并简化消费代码的实现 我已经对ActiveMQ、RabbitMQ和HornetQ做了一些研究,但是我没有看到一个明显的实现方法 ActiveMQ支持使

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

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

我已经对ActiveMQ、RabbitMQ和HornetQ做了一些研究,但是我没有看到一个明显的实现方法

ActiveMQ支持使用者订阅通配符,但我看不到将每个队列上的并发性限制为1的方法。如果我能做到这一点,那么解决方案将非常简单:

以某种方式告诉代理允许以:/queue/person开头的所有队列的并发性为1。 Publisher使用队列名称中的人员ID将事件写入队列。e、 g.:/queue/人。20 消费者使用通配符订阅队列:/queue/person.> 每个消费者将收到不同人员队列的消息。如果所有人员队列都在使用中,一些消费者可能会无所事事,这是正常的 在处理一条消息之后,使用者发送一个ACK,告知代理消息已处理完毕,并允许将该人员队列的另一条消息发送给另一个使用者(可能是同一个使用者) ActiveMQ很接近:您可以进行通配符订阅并启用独占使用者,但这种组合会导致单个使用者接收发送到所有匹配队列的所有消息,从而将所有人员的并发性降低到1。我觉得我错过了一些明显的东西

问题:

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

如果您已经有了一个允许共享锁的系统,为什么不为每个队列都设置一个锁,消费者在从队列中读取数据之前必须获得该锁?

如果我正确地解决了您的问题,一个解决此问题的通用方法是为用户引入一些独特的属性,例如,人员的数据库级别id,并使用该属性的哈希作为FIFO队列的索引将该人员放入。 由于该属性的散列可能非常庞大,您负担不起2^32个队列/线程,请仅使用该散列中的N个最低有效位。 每个FIFO队列都应该有专门的工作人员来处理它-瞧,您的要求已经满足了


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

看起来像JMSXGUBPID是我正在寻找的。从ActiveMQ文档:


他们关于股票价格的示例用例正是我想要的。我唯一关心的是如果单个消费者死亡会发生什么。希望代理能够检测到这一点,并选择另一个消费者与该组id关联。

对于非轮询队列协议AMQP,STOMP代理将根据订阅规则向消费者发送消息。使用者可以查阅锁表并等待它可用,但这会带来复杂性并降低并行性,因为使用者可以处理另一个实体的消息,而不是等待锁。是的,但使用者不需要等待锁-它可以传递到下一个队列。您的排队协议可能还允许使用者拒绝从队列中读取消息,然后他们可以测试锁。在您的解决方案中,使用者是否仍然执行通配符订阅?如果是,如何确保每个队列只有一个活动使用者?或者,你是说我将队列名称向下散列,以便N==个活动消费者?@James很抱歉让你困惑,我谈论的是通用解决方案,没有考虑JMS。也就是说,只有线程和JDK集合。所以,在我的解决方案中,必须手动设置队列和使用者之间的映射-这通常很容易完成。啊,我理解。谢谢。看起来这完全有效。如果有人感兴趣,我已经针对ActiveMQ和HornetQ成功测试了一个python示例,用于解决这类问题:我找到了JMSXGroupID,看起来它是所有JMS实现所必需的。但是它没有详细解释预期的行为,那么将取决于提供者