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
观察到设置了优先级的消息被先消费了,证明我们的测试通过。
---------------
我每一次回头,都感觉自己不够努力,所以我不再回头。
---------------