MQ三大主要功能:削峰、异步、解耦,这章主要是讲削峰,可以通过MQ消费端限流来实现。
消费端限流主要是为了保证消费端的服务稳定性,防止超过消费端负载,将服务打挂,卡死。
rabbitmq提供了一种qos(服务质量保证)功能,即在非自动确认消息的前提下,如果一定数目的消息(给channel或者consume设置Qos值)未被确认前,不进行消费新消息。
使用:
1.在消费端,通过channel.basicQos方法进行设置
2.关闭自动ACK
测试
生产端:
package com.vivo.demo1.consumelimit;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @author:luzaichun
* @Date:2020/12/23
* @Time:22:10
**/
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setVirtualHost("/");
factory.setPort(5672);
factory.setHost("192.168.3.7");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
for (int i = 0; i < 5 ; i++) {
channel.basicPublish("limit_exchange","topic.limit",true,null,"limit测试".getBytes());
}
}
}
消费端:
package com.vivo.demo1.consumelimit;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @author:luzaichun
* @Date:2020/12/23
* @Time:22:18
**/
public class Consumer {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setVirtualHost("/");
factory.setHost("192.168.3.7");
factory.setPort(5672);
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare("limit_exchange","topic",false,false,null);
channel.queueDeclare("limit_queue",false,false,false,null);
channel.queueBind("limit_queue","limit_exchange","topic.#");
/**
*第一个参数:prefetchSize消息的大小限制,0不做限制
*第二个参数:prefetchCount一次最多推送多少消息,ack完后,再推这么多过来
* 第三个参数:global 限流策略应用级别。true-通道channel级别限制 false-consumer级别限制
* */
channel.basicQos(0,1,false);
//限流,autoAck一定要设置为false
channel.basicConsume("limit_queue",false,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
super.handleDelivery(consumerTag, envelope, properties, body);
System.out.println("消费端接收到消息:"+new String(body));
System.out.println("=======================");
//channel.basicAck(envelope.getDeliveryTag(),false);
}
});
}
}
我们先注释掉ack,观察:
可以看到消费端只接收到了一条消息,并且控制台看到queue里,有1条unack消息。4条ready消息,还没到达consumer。和我们设置的prefetchCount=1限流情况相符。
prefetchCount=1时候,mq一次给consumer推送1条消息,收到ack后才会继续推送下一条消息
打开ack,重新测试:
可以看到consuemr将5条消息都消费完了,因为每条消息都回送了ack。控制台队列中也没有ready状态,unack状态消息了。