rabbitmq的消费端限流模式(二)

rabbitmq的消费端限流模式

 

 

rabbitmq-high-producer项目

application.properties文件

server.port=8081
# ip
spring.rabbitmq.host=127.0.0.1
#默认5672
spring.rabbitmq.port=5672
#用户名
spring.rabbitmq.username=guest
#密码
spring.rabbitmq.password=guest
#连接到代理时用的虚拟主机
spring.rabbitmq.virtual-host=/
#是否启用【发布确认】,默认false
#spring.rabbitmq.publisher-confirm-type=correlated替换spring.rabbitmq.publisher-confirms=true
spring.rabbitmq.publisher-confirm-type=correlated
#是否启用【发布返回】,默认false
spring.rabbitmq.publisher-returns=true
#表示消息确认方式,其有三种配置方式,分别是none、manual和auto;默认auto
spring.rabbitmq.listener.simple.acknowledge-mode=manual
#rabbitmq限流,必须在ack确认才能使用
#消费者最小数量
spring.rabbitmq.listener.simple.concurrency=1
#最大的消费者数量
spring.rabbitmq.listener.simple.max-concurrency=10
#在单个请求中处理的消息个数,他应该大于等于事务数量(unack的最大数量)
spring.rabbitmq.listener.simple.prefetch=2

controller层

package com.qingfeng.rabbitmqhighproducer.qsq.controller;

import com.qingfeng.rabbitmqhighproducer.qsq.service.QsqRabbitService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

/**
 * 消费端限流
 */
@RestController
@RequestMapping("/qsq")
public class QsqDirectSendMessageController {

    @Autowired
    private QsqRabbitService qsqRabbitService;

    //http://127.0.0.1:8081/qsq/sendDirectMessage
    @GetMapping("/sendDirectMessage")
    public String sendDirectMessage() {
        for (int i=1;i<100;i++) {
            String messageId = String.valueOf(UUID.randomUUID());
            //将消息携带绑定键值:路由键MqConst.ROUTING_MSM_ITEM 发送到交换机MqConst.EXCHANGE_DIRECT_MSM
            qsqRabbitService.sendMessageQsq("qsq_direct_exchange", "qsq_direct_routing", messageId);
        }
        return "ok";
    }

    @GetMapping("/sendDirectMessage02")
    public String sendDirectMessage02() {
        String messageId = String.valueOf(UUID.randomUUID());

        //将消息携带绑定键值:路由键MqConst.ROUTING_MSM_ITEM 发送到交换机MqConst.EXCHANGE_DIRECT_MSM
        qsqRabbitService.sendMessageQsq("qsq_direct_exchange","qsq_direct_routing",messageId);
        return "ok";
    }

}
QsqRabbitConfig类
package com.qingfeng.rabbitmqhighproducer.qsq.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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 *限流机制
 */
@Configuration
public class QsqRabbitConfig {

    //交换机名称
    public static final String QSQ_DIRECT_EXCHANGE = "qsq_direct_exchange";
    //队列名称
    public static final String QSQ_DIRECT__QUEUE = "qsq_direct_queue";
    //路由
    public static final String QSQ_DIRECT__ROUTING = "qsq_direct_routing";

    /**
     * 交换机
     */
    @Bean(name = "qsqDirectExchange")
    public DirectExchange qsqDirectExchange() {
        // 参数意义:
        // name: 名称
        // durable: true
        // autoDelete: 自动删除
        return new DirectExchange(QSQ_DIRECT_EXCHANGE, true, false);
    }

    /**
     * 队列
     */
    @Bean(name ="qsqDirectQueue" )
    public Queue qsqDirectQueue() {
        // 参数意义:
        // name: 名称
        // durable: true为持久化
        return new Queue(QSQ_DIRECT__QUEUE, true);
    }

    /**
     * 绑定队列和交换机
     */
    @Bean
    public Binding bindingDirectQsq() {
        return BindingBuilder.bind(qsqDirectQueue())
                .to(qsqDirectExchange())
                .with(QSQ_DIRECT__ROUTING);
    }


}
QsqRabbitService类
package com.qingfeng.rabbitmqhighproducer.qsq.service;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.UUID;

@Service
public class QsqRabbitService implements RabbitTemplate.ConfirmCallback {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 消息从 producer生产者 到 exchange交换机 则会返回一个 confirmCallback 。
     *  producer发送消息confirm 确认模式
     * @param exchange 交换机
     * @param routingKey 路由键
     * @param msg 消息
     */
    public void sendMessageQsq(String exchange, String routingKey, String msg){
        /**
         * 确认模式:
         * 步骤:
         * 1. 确认模式开启:spring.rabbitmq.publisher-confirm-type=correlated
         * 2. 在rabbitTemplate定义ConfirmCallBack回调函数
         */
        //2. 定义回调
        rabbitTemplate.setConfirmCallback(this);
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        System.out.println("发送的消息为"+msg);
        this.rabbitTemplate.convertAndSend(exchange,routingKey,msg,correlationData);
    }

    /**
     *
     * @param correlationData 相关配置信息
     * @param ack   exchange交换机 是否成功收到了消息。true 成功,false代表失败
     * @param cause 失败原因
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        System.out.println("消息id:" + correlationData.getId());
        if (ack) {
            System.out.println("消息发送确认成功");
        } else {
            System.out.println("消息发送确认失败:" + cause);
        }
    }

}

 

 

rabbitmq-high-consumer项目

application.properties文件

server.port=8082

# ip
spring.rabbitmq.host=127.0.0.1
#默认5672
spring.rabbitmq.port=5672
#用户名
spring.rabbitmq.username=guest
#密码
spring.rabbitmq.password=guest
#连接到代理时用的虚拟主机
spring.rabbitmq.virtual-host=/
#是否启用【发布确认】,默认false
#spring.rabbitmq.publisher-confirm-type=correlated替换spring.rabbitmq.publisher-confirms=true
spring.rabbitmq.publisher-confirm-type=correlated
#是否启用【发布返回】,默认false
spring.rabbitmq.publisher-returns=true
#表示消息确认方式,其有三种配置方式,分别是none、manual和auto;默认auto
spring.rabbitmq.listener.simple.acknowledge-mode=manual
#rabbitmq限流,必须在ack确认才能使用
#消费者最小数量
spring.rabbitmq.listener.simple.concurrency=1
#最大的消费者数量
spring.rabbitmq.listener.simple.max-concurrency=10
#在单个请求中处理的消息个数,他应该大于等于事务数量(unack的最大数量)
spring.rabbitmq.listener.simple.prefetch=2
QsqRabbitConfig类
package com.qingfeng.rabbitmqhighconsumer.qsq;

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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 *限流机制
 */
@Configuration
public class QsqRabbitConfig {

    //交换机名称
    public static final String QSQ_DIRECT_EXCHANGE = "qsq_direct_exchange";
    //队列名称
    public static final String QSQ_DIRECT__QUEUE = "qsq_direct_queue";
    //路由
    public static final String QSQ_DIRECT__ROUTING = "qsq_direct_routing";

    /**
     * 交换机
     */
    @Bean(name = "qsqDirectExchange")
    public DirectExchange qsqDirectExchange() {
        // 参数意义:
        // name: 名称
        // durable: true
        // autoDelete: 自动删除
        return new DirectExchange(QSQ_DIRECT_EXCHANGE, true, false);
    }

    /**
     * 队列
     */
    @Bean(name ="qsqDirectQueue" )
    public Queue qsqDirectQueue() {
        // 参数意义:
        // name: 名称
        // durable: true为持久化
        return new Queue(QSQ_DIRECT__QUEUE, true);
    }

    /**
     * 绑定队列和交换机
     */
    @Bean("bindingDirectQsq")
    public Binding bindingDirectQsq() {
        return BindingBuilder.bind(qsqDirectQueue())
                .to(qsqDirectExchange())
                .with(QSQ_DIRECT__ROUTING);
    }




}
QsqListener类
package com.qingfeng.rabbitmqhighconsumer.qsq;

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * Consumer 限流机制
 *  1. 确保ack机制为手动确认。 spring.rabbitmq.listener.simple.acknowledge-mode=manual
 *  2. listener-container配置属性  spring.rabbitmq.listener.simple.prefetch=1
 *      perfetch = 1,表示消费端每次从mq拉去一条消息来消费,直到手动确认消费完毕后,才会继续拉去下一条消息。
 */
@Component
public class QsqListener {

    //限流机制
    @RabbitHandler
    @RabbitListener(queues = "qsq_direct_queue")
    public void onMessage(Message message, Channel channel) throws Exception {
        Thread.sleep(5000);
        //1.获取消息
        System.out.println(new String(message.getBody()));

        //2. 处理业务逻辑
        System.out.println("处理业务逻辑");

        //3. 签收
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),true);
    }
}

 

 

启动两个项目测试:正确的测试
访问http://127.0.0.1:8081/qsq/sendDirectMessage
rabbitmq-high-provider输出结果
会把生产的消息全发送到MQ服务器



rabbitmq-high-consumer输出结果
 
在配置文件里配置了spring.rabbitmq.listener.simple.prefetch=2
 
consumer两个两个的消费

 

 

 

 

 




 

posted @ 2021-04-23 17:48  Amy清风  阅读(334)  评论(0编辑  收藏  举报