文章目录

  • 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 页面也可以看出一共有十个消费者

javaspringboot高并发解决方案 springboot接口高并发_Data

第二种方式就是自定义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 管理页面中可以发现

javaspringboot高并发解决方案 springboot接口高并发_java_02


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;
    }
    }

结果和上面一致,这里不做阐述了。