概述
如果RabbitMQ服務器上有成千上萬條未處理的消息,如果我們這時我們運行消費端,一瞬間就會有巨量的消息推送過來,這個時候接收者因爲流量的劇增,超過了自己系統本身所能處理的最大峯值,如果沒有對消息做限流措施,接收服務器可能就會內存溢出,造成服務器不可用。
RabbitMQ限流機制
RabbitMQ提供了QOS限流功能,在非自動確認消息的前提下,如果有一定數目的未被確認前,不消費新的消息。
在消費端開啓限流機制
- 把
channel.basicConsume(...)
方法的autoAck
參數改爲false - 設置Qos
channel.basicQos(0,1,false);
/**
* @param prefetchSize 消息的大小,設置爲0不做任何限制
* @param prefetchCount 每次消費消息數
* @param global 爲true channel級別的限流,false 消費端限流
*/
void basicQos(int prefetchSize, int prefetchCount, boolean global) throws IOException;
代碼演示
- 生產端
public static void main(String[] args) throws Exception{
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
//設置虛擬主機
connectionFactory.setVirtualHost("/");
//創建一個鏈接
Connection connection = connectionFactory.newConnection();
//創建channel
Channel channel = connection.createChannel();
String exchangeName="test_qos_exchange";
String routeKey="qos.test";
String msg="RabbitMQ QOS message QOS test!";
for (int i=0;i<=4;i++){
channel.basicPublish(exchangeName,routeKey,null,msg.getBytes());
}
}
- 消費端
public static void main(String[] args) throws Exception{
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
//設置虛擬主機
connectionFactory.setVirtualHost("/");
//創建鏈接
Connection connection = connectionFactory.newConnection();
//創建channel
Channel channel = connection.createChannel();
String exchangeName="test_qos_exchange";
String exchangeType="topic";
//聲明Exchange
channel.exchangeDeclare(exchangeName,exchangeType,true,false,false,null);
String queueName="test_qos_queue";
//聲明隊列
channel.queueDeclare(queueName,true,false,false,null);
String routeKey="qos.#";
//綁定隊列和交換機
channel.queueBind(queueName,exchangeName,routeKey);
//設置限流
channel.basicQos(0,1,false);
/**
* 把autoAck設置爲false,限流才生效
*/
channel.basicConsume(queueName, false, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("接收到消息::"+new String(body));
//不批量簽收
channel.basicAck(envelope.getDeliveryTag(),false);
}
});
}
如果想看限流效果可先把消費端的這行代碼channel.basicAck(envelope.getDeliveryTag(),false);
先註釋。
在RabbitMQ控制檯可以看到,有4條消息未被消費,一條消息等待簽收確認。只有當前消息簽收後,才消費剩餘的消息