RabbitMQ队列和消息的优先级

RabbitMQ队列和消息的优先级

如果队列中的消息很多,需要一部分消息被优先消费,这是可以通过为消息和队列设置优先级来实现。

请注意,消息的优先级是相对于队列的优先级而言的。如果队列的最大优先级是10,那么消息的优先级可以在1到10的范围内设置。

MQ测试结构

代码实现

设置交换机和队列

package com.zjw.config;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Map;

/**
 * 设置队列的优先级
 */
@Configuration
public class PriorityConfig {

    public static final String PRIORITY_EXCHANGE_NAME = "priority.exchange";
    public static final String PRIORITY_QUEUE_NAME = "priority.queue";
    public static final String PRIORITY_ROUTING_KEY = "key1";

    /**
     * 创建优先级交换机
     * @return 交换机
     */
    @Bean("priorityExchange")
    public DirectExchange priorityExchange(){
        return new DirectExchange(PRIORITY_EXCHANGE_NAME);
    }

    /**
     * 创建优先级队列
     * @return 队列
     */
    @Bean("priorityQueue")
    public Queue priorityQueue(){
        Map<String, Object> args = Map.of("x-max-priority", 10);
        return new Queue(PRIORITY_QUEUE_NAME,true,false,false,args);
    }

    /**
     * 队列和交换机绑定
     */
    @Bean
    public Binding bindingPriorityQueue(@Qualifier("priorityQueue") Queue queue,
                                        @Qualifier("priorityExchange") DirectExchange priorityExchange) {
        return BindingBuilder.bind(queue).to(priorityExchange).with(PRIORITY_ROUTING_KEY);

    }
}

生产者

package com.zjw.controller;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

import static com.zjw.config.PriorityConfig.PRIORITY_EXCHANGE_NAME;
import static com.zjw.config.PriorityConfig.PRIORITY_ROUTING_KEY;


/**
 * 发送优先级消息
 * <p>
 * 消息的优先级是相对于队列的优先级而言的。如果队列的最大优先级是10,那么消息的优先级可以在1到10的范围内设置。
 */
@AllArgsConstructor
@Slf4j
@RestController
@RequestMapping("/priority")
public class SendPriorityMsgController {

    private RabbitTemplate rabbitTemplate;

    /**
     * 生产者发送消息
     *
     * @param message 消息
     */
    @GetMapping("sendMsg/{message}")
    public void sendMsg(@PathVariable String message) {
        log.info("当前时间:{},发送优先级消息给priority.queue队列:{}", new Date(), message);
        // 连续发送送10条消息,偶数设置优先级高一点
        for (int i = 0; i < 10; i++) {
            if (i % 2 == 0) {
                MessagePostProcessor messagePostProcessor = msg -> {
                    MessageProperties properties = msg.getMessageProperties();
                    properties.setPriority(5);
                    return msg;
                };
                rabbitTemplate.convertAndSend(PRIORITY_EXCHANGE_NAME, PRIORITY_ROUTING_KEY, message + i, messagePostProcessor);
            } else {
                rabbitTemplate.convertAndSend(PRIORITY_EXCHANGE_NAME, PRIORITY_ROUTING_KEY, message + i + message);
            }

        }
    }
}

消费者

package com.zjw.consumer;

import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * 消费优先级队列消费者
 */
@Slf4j
@Component
public class PriorityQueueConsumer {

    @RabbitListener(queues = {"priority.queue"})
    public void receiveD(Message message, Channel channel) {
        String msg = new String(message.getBody());
        log.info("当前时间:{},收到优先级队列的消息:{}", new Date(), msg);
    }
}

测试

我这里先关闭消费者,却被消息还没有被消费。等生产者发送消息后,再开启消费者。

通过访问 http://localhost:8080/priority/sendMsg/hello 来让消费者发送消息。
生产者日志打印

2024-01-11T19:25:45.044+08:00  INFO 19184 --- [nio-8080-exec-4] c.z.c.SendPriorityMsgController          : 当前时间:Thu Jan 11 19:25:45 CST 2024,发送优先级消息给priority.queue队列:hello

打开消费者服务,消费消息
日志打印

2024-01-11T19:25:55.418+08:00  INFO 14252 --- [ntContainer#3-1] com.zjw.consumer.PriorityQueueConsumer   : 当前时间:Thu Jan 11 19:25:55 CST 2024,收到优先级队列的消息:hello0
2024-01-11T19:25:55.421+08:00  INFO 14252 --- [ntContainer#3-1] com.zjw.consumer.PriorityQueueConsumer   : 当前时间:Thu Jan 11 19:25:55 CST 2024,收到优先级队列的消息:hello2
2024-01-11T19:25:55.421+08:00  INFO 14252 --- [ntContainer#3-1] com.zjw.consumer.PriorityQueueConsumer   : 当前时间:Thu Jan 11 19:25:55 CST 2024,收到优先级队列的消息:hello4
2024-01-11T19:25:55.422+08:00  INFO 14252 --- [ntContainer#3-1] com.zjw.consumer.PriorityQueueConsumer   : 当前时间:Thu Jan 11 19:25:55 CST 2024,收到优先级队列的消息:hello6
2024-01-11T19:25:55.422+08:00  INFO 14252 --- [ntContainer#3-1] com.zjw.consumer.PriorityQueueConsumer   : 当前时间:Thu Jan 11 19:25:55 CST 2024,收到优先级队列的消息:hello8
2024-01-11T19:25:55.423+08:00  INFO 14252 --- [ntContainer#3-1] com.zjw.consumer.PriorityQueueConsumer   : 当前时间:Thu Jan 11 19:25:55 CST 2024,收到优先级队列的消息:hello1hello
2024-01-11T19:25:55.423+08:00  INFO 14252 --- [ntContainer#3-1] com.zjw.consumer.PriorityQueueConsumer   : 当前时间:Thu Jan 11 19:25:55 CST 2024,收到优先级队列的消息:hello3hello
2024-01-11T19:25:55.424+08:00  INFO 14252 --- [ntContainer#3-1] com.zjw.consumer.PriorityQueueConsumer   : 当前时间:Thu Jan 11 19:25:55 CST 2024,收到优先级队列的消息:hello5hello
2024-01-11T19:25:55.424+08:00  INFO 14252 --- [ntContainer#3-1] com.zjw.consumer.PriorityQueueConsumer   : 当前时间:Thu Jan 11 19:25:55 CST 2024,收到优先级队列的消息:hello7hello
2024-01-11T19:25:55.425+08:00  INFO 14252 --- [ntContainer#3-1] com.zjw.consumer.PriorityQueueConsumer   : 当前时间:Thu Jan 11 19:25:55 CST 2024,收到优先级队列的消息:hello9hello

观察到设置了优先级的消息被先消费了,证明我们的测试通过。

posted @ 2024-01-11 19:27  雨中遐想  阅读(65)  评论(0编辑  收藏  举报