是";“公平排队”;使用JMS是可能的

是";“公平排队”;使用JMS是可能的,jms,hornetq,Jms,Hornetq,我需要实现一个公平的排队系统,以便根据当前排队的消息上某个消息头的所有值,以循环方式处理消息 系统中的消息自然地按某些属性分组,其中有数千个可能的值,并且当前排队的消息的值集随时间而变化。类似的情况是,在消息创建时,消息头是时间的毫秒部分。因此,标头的值将介于0和999之间,并且该值将在当前排队的所有消息中进行某种分布 我需要能够以这样的顺序使用消息,即没有特定的值优先于任何其他值。如果排队消息的头值是这样分布的 value | count ------|------- A | 3

我需要实现一个公平的排队系统,以便根据当前排队的消息上某个消息头的所有值,以循环方式处理消息

系统中的消息自然地按某些属性分组,其中有数千个可能的值,并且当前排队的消息的值集随时间而变化。类似的情况是,在消息创建时,消息头是时间的毫秒部分。因此,标头的值将介于0和999之间,并且该值将在当前排队的所有消息中进行某种分布

我需要能够以这样的顺序使用消息,即没有特定的值优先于任何其他值。如果排队消息的头值是这样分布的

value | count
------|-------
  A   |   3
  B   |   3
  C   |   2
然后消费顺序将是
A、B、C、A、B、C、A、B

如果将具有其他值的消息添加到队列中,则应将其自动添加到循环序列中

这意味着对当前排队的消息有一些了解,但不要求消费者掌握这些知识;代理可能具有以某种方式订购交付的机制

可以接受的是,如果超过某个阈值,将开始公平排队。也就是说,如果阈值是10,那么可以接受顺序处理10条具有相同值的消息,但是处理的第11条消息应该是顺序中的下一个值。如果只有排队的消息具有该值,则Next可能是相同的值

可能值的数量可能会排除为每个值创建一个队列并迭代队列的可能性,尽管这尚未经过测试

我们使用的是HornetQ,但如果有提供这些语义的替代方案,那么我很想知道

消息是作业,标题值是用户ID。所寻求的是,在某些限制范围内,任何给定用户的作业都不会不适当地延迟任何其他用户的作业;产生100万个作业的用户不会导致其他用户稍后的作业等待处理这100万个作业

HornetQ中队列上的消费者按创建顺序进行评估,因此将选择性消费者添加到队列不会阻止任何catch all消费者接收与筛选器匹配的消息

JMS组似乎没有帮助,因为这将给定的组(用户?)与给定的消费者联系起来


一个潜在的解决方案是根据需求(例如:来自同一用户的10条连续消息)在某个主题上创建选择性消费者,并对所有选择性消费者的生命周期进行管理,以确保catch all不会处理相同的消息。虽然这可能有一些繁琐的同步要求。

考虑的第一个选项是拥有多线程的消费应用程序。假设每个会话/使用者有一个线程,则可以使用选择器设置同步或异步接收。每个选择器将被键入特定的用户

假设JVM在线程调度方面是合理的(我很乐意假设),并且应用程序代码中没有任何死锁,我断言需求将得到满足。一个线程可能会被一百万个用户的作业卡住,其余的不会受到影响


然而,如果需要单线程应用程序,那么JMS规范中的任何内容及其本身都不会有帮助。他们可能是供应商的扩展,这当然会有所帮助。但是,另一个选项是应用程序查看每条消息,并将其放在用户id的特定队列中。最终的消费应用程序本身将在这些队列之间“循环”以获得工作。需要另一个应用程序,但您有一个非常确定的系统

我建议使用消息优先级+设置consumerWindowSize=0,并始终让客户端从服务器上选择新消息

您可能会有更多的消息延迟,但始终会有来自服务器的消息

注意你需要考虑的种族。如果您正在使用消息C,消息B已到达,该怎么办?然后,您将在以后的消费B中消费C。但由于C已经在消费中,所以您在这方面做不了多少


您也可以考虑消息分组,但您将从负载平衡将消息组绑定到单个用户。

< P>您希望JMS代理实现消息传递算法(公平队列),据我所知,这不是JMS规范的一部分。也许可以找到一种让经纪人这样做的方法,但我对此表示怀疑,而且您提出的任何解决方案都可能是特定于经纪人的

相反,为什么不在您自己的应用程序中使用所需的排队算法呢?例如:编写一个“公平队列转发器(FQF)”应用程序,该应用程序订阅所有消息,无论消息来自代理的顺序如何。让此FQF应用程序尽可能快地使用消息,以便JMS代理队列始终为空或接近空。然后,FQF应用程序可以将消息存储在本地队列中,并按照所需的队列算法确定的顺序,将消息一次重新发布到最终消息处理应用程序订阅的队列或主题中。在这方面,您可能希望使用事务或某种流控制,以便FQF应用程序仅以终端系统可以处理的速率发布消息

根据您的示例,这些消息表示要根据消息头中的用户id属性按特定顺序处理的作业。所以我建议您编写一个作业调度算法,使用您想要的任何排队算法将作业传递给作业处理器

这样,您就可以完全控制
String queueName = "Q" + user.hashCode()%100;