简体   繁体   English

Spring AMQP RabbitMQ实现优先级队列

[英]Spring AMQP RabbitMQ implementing priority queue

After Google for a few days, and i believe i am totally lost. 谷歌待了几天,我相信我完全迷失了。 I would like to implement a kind of priority queue that has about 3 queues: 我想实现一种有大约3个队列的优先级队列:

  1. high priority queue (daily), that needs to be process first. 高优先级队列(每日),需要先处理。
  2. mid priority queue (weekly), that will process if no items in queue #1. 中间优先级队列(每周),如果队列#1中没有项目将处理。 (it is ok message in this queue it never process at all) (这个队列中的消息是好的,它根本不会处理)
  3. low priority queue (monthly), that will process if no items in queue #1 & #2. 低优先级队列(每月),如果队列#1和#2中没有项目将处理。 (it is ok message in this queue it never process at all) (这个队列中的消息是好的,它根本不会处理)

Initially I have the following flow, to have a consumer to consume messages from all three queues and checks whether there is any items in queue #1, #2 and #3. 最初,我有以下流程,让消费者使用来自所有三个队列的消息,并检查队列#1,#2和#3中是否有任何项目。 and then I realize that this is wrong because: 然后我意识到这是错误的,因为:

  1. I am totally lost with a question: "How do I know which queue it is coming from?". 我完全迷失了一个问题:“我怎么知道它来自哪个队列?”。
  2. I'm already consuming a message regardless from any queue, So if I get an object from lower priority queue, am I gonna put it back to the queue if I discover there is a message at the higher priority queue? 我已经在消耗任何队列中的消息了,所以如果我从较低优先级队列中获取一个对象,如果我发现优先级较高的队列中有消息,我会把它放回队列吗?

Following is my current configurations, which shows what an idiot I am. 以下是我目前的配置,它显示了我是个白痴。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit-1.0.xsd">

<rabbit:connection-factory id="connectionFactory" host="localhost" />

<rabbit:template id="amqpTemplatead_daily" connection-factory="connectionFactory"
    exchange="" routing-key="daily_queue"/>

<rabbit:template id="amqpTemplatead_weekly" connection-factory="connectionFactory"
    exchange="" routing-key="weekly_queue"/>

<rabbit:template id="amqpTemplatead_monthly" connection-factory="connectionFactory"
    exchange="" routing-key="monthly_queue"/>

<rabbit:admin connection-factory="connectionFactory" />

<rabbit:listener-container connection-factory="connectionFactory">
    <rabbit:listener ref="Consumer" method="consume" queue-names="daily_queue" />
</rabbit:listener-container>

<rabbit:listener-container connection-factory="connectionFactory">
    <rabbit:listener ref="Consumer" method="consume" queue-names="weekly_queue" />
</rabbit:listener-container>    

<rabbit:listener-container connection-factory="connectionFactory">
    <rabbit:listener ref="Consumer" method="consume" queue-names="monthly_queue" />
</rabbit:listener-container>    

<bean id="Consumer" class="com.test.Consumer" />

</beans>

Any idea how should I tackle this with priority queue? 知道如何用优先级队列解决这个问题?

ps: I also wonder, if Apache Camel has something I can depend on? ps:我也想知道,如果Apache Camel有我可以依赖的东西吗?

UPDATE 1: I just saw this from Apache Camel: " https://issues.apache.org/jira/browse/CAMEL-2537 " the sequencer on JMSPriority seems to be what im looking for, anyone has tried this before? 更新1:我刚从Apache Camel看到这个:“ https://issues.apache.org/jira/browse/CAMEL-2537 ”JMSPriority上的音序器似乎是我正在寻找的,任何人都曾尝试过这个吗?

UPDATE 2: assuming i am to use RabbitMQ's plugin base on @Gary Russell recommendation, I have the following spring-rabbitmq context XML configuration, which seems to make sense (by guest..): 更新2:假设我在@Gary Russell推荐下使用RabbitMQ的插件,我有以下spring-rabbitmq上下文XML配置,这似乎有意义(由guest ..):

<rabbit:queue name="ad_google_dfa_reporting_queue">
    <rabbit:queue-arguments>
            <entry key="x-max-priority" value="10"/>
    </rabbit:queue-arguments>
</rabbit:queue>

<rabbit:listener-container connection-factory="connectionFactory">
    <rabbit:listener ref="adGoogleDfaReporting" method="consume" queue-names="ad_google_dfa_reporting_queue" />
</rabbit:listener-container>

<bean id="Consumer" class="com.test.Consumer" />

The above xml configuration has successfully create a Queue, with name: "ad_google_dfa_reporting_queue", and with Parameter arguments: x-max-priority: 10 & durable: true 上面的xml配置已成功创建一个名称为“ad_google_dfa_reporting_queue”的队列,并带有参数参数:x-max-priority:10&durable:true

But not when comes to the code that send the message with priority , I totally lost it. 但是,当没有优先发送消息的代码时,我完全失去了它。 How to define the priority as mention in the Sample URL: https://github.com/rabbitmq/rabbitmq-priority-queue/blob/master/examples/java/src/com/rabbitmq/examples/PriorityQueue.java 如何在示例URL中定义优先级: https//github.com/rabbitmq/rabbitmq-priority-queue/blob/master/examples/java/src/com/rabbitmq/examples/PriorityQueue.java

AmqpTemplate amqpTemplateGoogleDfaReporting = (AmqpTemplate) applicationContext.getBean("amqpTemplateadGoogleDfaReporting");
amqpTemplateGoogleDfaReporting.convertAndSend("message"); // how to define message priority?

UPDATE 3: Based on the @Gary's answer, i manage to sent message with priority set in the message, as per image below: 更新3:根据@Gary的答案,我设法发送消息中设置了优先级的消息,如下图所示: 消息优先截图 However, when i sent in 1000 messages with random priority between 1-10, the consumer is consuming message with all kinds of priority. 但是,当我发送1000条随机优先级在1-10之间的消息时,消费者正在消费具有各种优先级的消息。 (I was expecting only the high priority message to be consume first). (我原本只期望首先使用高优先级消息)。 following is the code for Message producer: 以下是Message producer的代码:

    Random random = new Random();
    for (int i=0; i< 1000; i++){
        final int priority = random.nextInt(10 - 1 + 1) + 1;

        DfaReportingModel model = new DfaReportingModel();
        model.setReportType(DfaReportingModel.ReportType.FACT);
        model.setUserProfileId(0l + priority);
        amqpTemplateGoogleDfaReporting.convertAndSend(model, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().setPriority(priority);
                return message;
            }
        });
    }

And following is the code for Message consumer: 以下是Message consumer的代码:

    public void consume(DfaReportingModel message) {
        System.out.println(message.getUserProfileId());

        Thread.sleep(500);
    }

The result im getting: 得到的结果:

9, 10, 7, 9, 6, 4, 10, 10, 3, 10, 6, 1, 5, 6, 6, 3, 4, 7, 6, 8, 3, 1, 4, 5, 5, 3, 10, 9, 5, 1, 8, 9, 6, 9, 3, 10, 7, 4, 8, 7, 3, 4, 8, 2, 6, 9, 6, 4, 7, 7, 2, 8, 4, 4, 1,

UPDATE 4: Problem solved! 更新4:问题解决了! Knowing the sample code from https://github.com/rabbitmq/rabbitmq-priority-queue is working in my environment, I presume that the problem is around the spring context. 知道来自https://github.com/rabbitmq/rabbitmq-priority-queue的示例代码在我的环境中工作,我认为问题出在Spring环境中。 Hence, after countless time on try and error with different type of configurations, and I pin point the exact combination that will make this works! 因此,经过无数次尝试和错误与不同类型的配置,我指出确切的组合,这将使其工作! and is as per following: 如下:

    <rabbit:queue name="ad_google_dfa_reporting_queue">
    <rabbit:queue-arguments>
        <entry key="x-max-priority">
            <value type="java.lang.Integer">10</value> <!-- MUST specifically define java.lang.Integer to get it to work -->
        </entry>
    </rabbit:queue-arguments>
</rabbit:queue>

Without specifically define the value is Integer type, the priority queue does not work. 如果没有专门定义值为Integer类型,则优先级队列不起作用。 Finally, it is solved. 最后,它解决了。 Yay! 好极了!

RabbitMQ now has a priority queue plugin where messages are delivered in priority order. RabbitMQ现在有一个优先级队列插件 ,其中消息按优先级顺序传递。 It would be better to use that rather than your scheme of requeueing low priority messages which will be quite expensive at runtime. 使用它而不是重新排列低优先级消息的方案会更好,这些消息在运行时会非常昂贵。

EDIT: 编辑:

When using the rabbitTemplate.convertAndSend(...) methods, and you want to set the priority property on the message, you either need to implement a custom MessagePropertiesConverter in the template (subclass the DefaultMessagePropertiesConverter ) or use the convertAnSend variants that take a message post-processor; 使用rabbitTemplate.convertAndSend(...)方法时,如果要在消息上设置priority属性,则需要在模板中实现自定义MessagePropertiesConverterDefaultMessagePropertiesConverter子类)或使用带有消息的convertAnSend变体后处理器; eg: 例如:

template.convertAndSend("exchange", "routingKey", "message", new MessagePostProcessor() {

    @Override
    public Message postProcessMessage(Message message) throws AmqpException {
        message.getMessageProperties().setPriority(5);
        return message;
    }
});

RabbitMQ has priority queue implementation in the core as of version 3.5.0. 从版本3.5.0开始,RabbitMQ在核心中具有优先级队列实现。

You can declare priority queues using the x-max-priority argument. 您可以使用x-max-priority参数声明优先级队列。 This argument should be an integer indicating the maximum priority the queue should support. 此参数应为整数,指示队列应支持的最大优先级。 For example, using the Java client: 例如,使用Java客户端:

Channel ch = ...;
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-max-priority", 10);
ch.queueDeclare("my-priority-queue", true, false, false, args);

You can then publish prioritised messages using the priority field of basic.properties . 然后,您可以使用basic.properties的优先级字段发布优先级消息。 Larger numbers indicate higher priority. 数字越大表示优先级越高。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM