消息中间件--RabbitMQ --- 消费端限流 -- 非常重要

什么是消费端的·限流?

  1. 假设一个场景,首先,我们Rabbitmq服务器有上万条未处理的消息,我们随便打开一个消费者客户端,会出现下面的情况:
  2. 巨量的消息瞬间全部推送过来,但是我们单个客户端无法同时处理这么多数据!

注意:高并发情景下,生产端我们没办法做限制,所以我们只能限制消费端,防止消费端口资源耗尽。

RabbitMQ提供了一种qos(服务质量保证)功能,即在非自动确认消息的前提下,如果一定数目的消息(通过基于consume或者channel设置Qos的值)未被确认前,不进行消费新的消息。

消息中间件--RabbitMQ --- 消费端限流 -- 非常重要_第1张图片
消费端的方法
void BasicQos(uint prefetchSize, ushort prefetchCount,bool global)

消息中间件--RabbitMQ --- 消费端限流 -- 非常重要_第2张图片
prefetchSize: 0
prefetchCount : 最多消费的消息个数 ,一般设置为1
global : channel 级别或者 消费端级别,一般设置为false

消息中间件--RabbitMQ --- 消费端限流 -- 非常重要_第3张图片

注意:自动设置签收一定要设置为false,autoAck = false

代码如下:

package com.bfxy.rabbitmq.api.limit;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.QueueingConsumer;
import com.rabbitmq.client.QueueingConsumer.Delivery;

public class Consumer {

	
	public static void main(String[] args) throws Exception {
		
		
		ConnectionFactory connectionFactory = new ConnectionFactory();
		connectionFactory.setHost("localhost");
//		connectionFactory.setHost("192.168.43.223");
		connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		connectionFactory.setUsername("guest");
		connectionFactory.setPassword("guest");
		
		Connection connection = connectionFactory.newConnection();
		Channel channel = connection.createChannel();
		
		
		String exchangeName = "test_qos_exchange";
		String queueName = "test_qos_queue";
		String routingKey = "qos.#";
		
		channel.exchangeDeclare(exchangeName, "topic", true, false, null);
		channel.queueDeclare(queueName, true, false, false, null);
		channel.queueBind(queueName, exchangeName, routingKey);
		
	
		// 0代表不限制大小,1条结束再给我,false代表应用到consumer级别
		channel.basicQos(0, 1, false);
		
		//1 限流方式  第一件事就是 autoAck设置为 false , 第二个参数
		channel.basicConsume(queueName, false, new MyConsumer(channel));
	}
}

package com.bfxy.rabbitmq.api.limit;

import java.io.IOException;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;

public class MyConsumer extends DefaultConsumer {


	private Channel channel ;
	
	public MyConsumer(Channel channel) {
		super(channel);
		this.channel = channel;
	}

	@Override
	public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
		System.err.println("-----------consume message----------");
		System.err.println("consumerTag: " + consumerTag);
		System.err.println("envelope: " + envelope);
		System.err.println("properties: " + properties);
		System.err.println("body: " + new String(body));
		
		// false 不批量签收
		// 	channel.basicAck(envelope.getDeliveryTag(), false); 可以注释试试
		channel.basicAck(envelope.getDeliveryTag(), false);
		
	}


}

生产者代码

package com.bfxy.rabbitmq.api.consumer;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class Producer {

	
	public static void main(String[] args) throws Exception {
		
		ConnectionFactory connectionFactory = new ConnectionFactory();

		connectionFactory.setHost("localhost");
//		connectionFactory.setHost("192.168.43.223");
		connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		connectionFactory.setUsername("guest");
		connectionFactory.setPassword("guest");
		
		Connection connection = connectionFactory.newConnection();
		Channel channel = connection.createChannel();
		
		String exchange = "test_consumer_exchange";
		String routingKey = "consumer.save";
		
		String msg = "Hello RabbitMQ Consumer Message";
		//这里可以改成 50000 , 可以看出来mq消费还是很快的
		for(int i =0; i<5; i ++){
			channel.basicPublish(exchange, routingKey, true, null, msg.getBytes());
		}
		
	}
}

结果如下:消费者正常消费5条信息
消息中间件--RabbitMQ --- 消费端限流 -- 非常重要_第4张图片

消费端不签收的话:
结果如下:只能有一条,其他的都在ready
在这里插入图片描述

消息中间件--RabbitMQ --- 消费端限流 -- 非常重要_第5张图片

你可能感兴趣的:(消息队列)