文章目录
- 1、高并发
- 2、限流
这篇文章我们来说一下利用RabbitMQ 解决高并发和限流的问题,我们这里都提供两种解决方案。这篇文章都是基于商量文章的基础来实现的。
1、高并发
第一种 :使用注解@RabbitListener
/**
* testDirectRabbit 是监听对列的名称
* concurrency min-max 表示并发数,表示有多少个消费者处理队列里的消息 最小-最大数
*/
@RabbitListener(queues = "testDirectQueue",concurrency="5-10")
public class DirectReceiver {
@RabbitHandler
public void process(Map testMessage){
System.out.println(Thread.currentThread().getName()+testMessage.toString());
}
}
发送消息的接口
@GetMapping("/sendDirectMessageForconcurrency")
public String sendDirectMessageForconcurrency(){
String messageId = String.valueOf(UUID.randomUUID());
String messageData = "test message, hello!";
String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Map<String,Object> map=new HashMap<>();
map.put("messageId",messageId);
map.put("messageData",messageData);
map.put("createTime", createTime);
//将消息携带绑定键值:testDirectRouting 发送到交换机testDirectExchange
for(int i=0;i<20;i++){
rabbitTemplate.convertAndSend("testDirectExchange","testDirectRouting", map);
}
return "ok";
}
调用该接口,查看控制台打印情况
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-9{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-1{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-2{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-8{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-4{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-5{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-3{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-7{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-6{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-10{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-7{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-9{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-3{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-8{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-4{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-5{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-10{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-6{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-2{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-1{createTime=2020-12-30 23:20:30, messageId=abac2a86-eead-4c2f-86d5-5fdd069ef497, messageData=test message, hello!}
从结果中可以发现总共有十个线程出来队列的消息。
从RaabitMQ 页面也可以看出一共有十个消费者
第二种方式就是自定义SimpleMessageListenerContainer 监听容器
@Bean
public SimpleMessageListenerContainer simpleMessageListenerContainer() {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(cachingConnectionFactory);
//设置最小并发的消费者数量
container.setConcurrentConsumers(10);
//设置最大并发的消费者数量
container.setMaxConcurrentConsumers(20);
//设置rabbit 确认消息的模式,默认是自动确认
container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
//设置一个队列
//container.setQueueNames("testDirectQueue");
//还可以设置多个队列
container.setQueueNames("testDirectQueue", "fanout.A");
//设置监听器,myAckReceiver 就是上面定义的监听类,这里不重复写了
container.setMessageListener(myAckReceiver);
return container;
}*/
启动项目,和上面的效果是一样的,这样不做阐述了。
2、限流
第一种使用使用注解@RabbitListener,使用containerFactory 指定监听容器
/**
* testDirectRabbit 是监听对列的名称
* containerFactory 指定自定义的 监听容器
*/
@RabbitListener(queues = "testDirectQueue",containerFactory = "listenerContainer")
public class DirectReceiver {
@RabbitHandler
public void process(Map testMessage){
System.out.println(Thread.currentThread().getName()+testMessage.toString());
}
}
自定义监听容器
@Configuration
public class MessageListenerConfig {
@Resource
private CachingConnectionFactory cachingConnectionFactory;
/**
* @return
* @Date 2020/12/30 17:01
* @Author jiangheng
* @Description //TODO 使用@RabbitListener注解的方式显示限流,主要指定SimpleRabbitListenerContainerFactory
**/
@Bean(name = "listenerContainer")
public SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory(){
SimpleRabbitListenerContainerFactory factory=new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(cachingConnectionFactory);
factory.setPrefetchCount(10);
return factory;
}
}
从RabbitMQ 管理页面中可以发现
prefetch count 就是我们设置的数量,默认值是 250
第二种方式就是自定义SimpleMessageListenerContainer 监听容器
public class MessageListenerConfig {
@Resource
private CachingConnectionFactory cachingConnectionFactory;
@Resource
private MyAckReceiver myAckReceiver;
/**
* @return
* @Date 2020/12/30 16:21
* @Author jiangheng
* @Description //TODO 自定义监听容器,不使用@RabbitListen 注解来消费消息,而是使用自定义的SimpleMessageListenerContainer来消费消息
**/
@Bean
public SimpleMessageListenerContainer simpleMessageListenerContainer() {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(cachingConnectionFactory);
//设置最小并发的消费者数量
//container.setConcurrentConsumers(10);
//设置最大并发的消费者数量
//container.setMaxConcurrentConsumers(20);
//限流,单位时间内消费多少条记录
container.setPrefetchCount(10);
//设置rabbit 确认消息的模式,默认是自动确认
container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
//设置一个队列
//container.setQueueNames("testDirectQueue");
//还可以设置多个队列
container.setQueueNames("testDirectQueue", "fanout.A");
//设置监听器
container.setMessageListener(myAckReceiver);
return container;
}
}
结果和上面一致,这里不做阐述了。