RabbitMQ工作队列

RabbitMQ工作队列模型允许一个生产者对应多个消费者,以提高消息处理速度。文章介绍了轮询分配和公平分发两种消息分配策略,以及生产者、消费者代码的实现。此外,还讲解了消息应答机制、自动确认模式与手动确认模式的差异,以及消息持久化的必要性和设置方法。在遇到rabbitmq故障时,持久化能防止消息丢失。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

模型:
在这里插入图片描述
一个生产者,对应多个消费者,可以弥补简单队列一对一的限制,在实际开发中,生产者生产消息速度往往很快,但是消费者消费消息时可能会有比较耗时的操作,如果是简单工作队列,那么将可能导致消息队列中积累很多的消息,多个消费者可以增加消费速度。

轮询分配消息:
如果采用轮询的方式将队列中的消息分配给每个消费者,那么其实现方式与简单队列没有区别,只不过消费者有多个,代码没有区别。

公平分发(fair dispatch)
轮询的方式导致每个消费者都消费差不多的消息,当消费者处理速度有差异的时候,造成执行速度快的消费者先执行完,执行慢的消费者后执行完,为了处理这种情况,可以使用公平分发,不采用轮询的方式,生产者在发送消息到消息队列的时候,告诉消息队列,每次消息队列收到消费者确认消息后只发送一条消息到消费者。而消费者取消自动应答模式,使用手动应答,即当消费者消费完消息,自己发送应答消息给消息队列。

生产者代码

public class Provider {
	private static final String QUNUE_NAME="test_qunue";
	public static void main(String args[]) throws Exception {
		
		//获取rabbitMQ连接
		Connection conn = RabbitMqUtil.getConnection();
		//创建channel
		Channel channel = conn.createChannel();
		//创建队列声明
		channel.queueDeclare(QUNUE_NAME, false, false, false, null);
		//每个消费者发送确认消息之前,消息队列不发送下一个消息到消费者,一次只处理一个消息
		//限制发送给同一个消费者不得超过一条消息
		int count = 1;
		channel.basicQos(count);
		
		//发送消息
		for(int i=0; i<50; i++) {
			String msg = "hello "+i;
			channel.basicPublish("", QUNUE_NAME, null, msg.getBytes());
		}
		
		channel.close();
		conn.close();
	}
}

代码与简单队列大致相同,channel.basicQos(count)告诉消息队列每次发送一条消息给消费者。

消费者代码

public class Reciver {
	private static final String QUNUE_NAME = "test_qunue";

	public static void main(String[] args) throws Exception {
		newApi();
	}

	public static void newApi() throws Exception {
		// 获取连接
		Connection conn = RabbitMqUtil.getConnection();
		// 创建channel
		final Channel channel = conn.createChannel();
		// 声明队列,如果生产者中声明了队列,消费者中可以不声明
		channel.queueDeclare(QUNUE_NAME, false, false, false, null);

		channel.basicQos(1);

		// 创建消费者
		Consumer consumer = new DefaultConsumer(channel) {
			// 当生产者发送消息到rabbitmq之后,会自动触发消费者中的handleDelivery方法
			public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
					byte[] body) throws IOException {

				try {
					String msg = new String(body, "UTF-8");
					System.out.println("msg1:" + msg);
					Thread.sleep(2000);
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					channel.basicAck(envelope.getDeliveryTag(), false);
				}
			}

		};
		// 监听队列,将自动应答关闭,使用手动应答
		boolean autoAck = false;
		channel.basicConsume(QUNUE_NAME, autoAck, consumer);
	}
}

消费者端需要告诉消息队列每次发送一个消息过来,处理完消息后手动返回确认消息

channel.basicAck(envelope.getDeliveryTag(), false);

消息应答

boolean autoAck = false;
channel.basicConsume(QUNUE_NAME, autoAck, consumer);

autoAck=true时,自动确认模式,一旦rabbitmq将消息分发给消费者后,就会从消息队列中将该条消息删除,那么在这种情况下,如果消费者发生故障,虽然接收到消息,但是没有来得及处理,结果该消息就丢失了。如下消费者,在手动发送确认之前执行1/0,发生异常,那么消息队列没有收到确认,会将消息发送给其他的消费者处理。

	public static void newApi() throws Exception {
		// 获取连接
		Connection conn = RabbitMqUtil.getConnection();
		// 创建channel
		final Channel channel = conn.createChannel();
		// 声明队列,如果生产者中声明了队列,消费者中可以不声明
		channel.queueDeclare(QUNUE_NAME, false, false, false, null);

		channel.basicQos(1);

		// 创建消费者
		Consumer consumer = new DefaultConsumer(channel) {
			// 当生产者发送消息到rabbitmq之后,会自动触发消费者中的handleDelivery方法
			public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
					byte[] body) throws IOException {

				try {
					String msg = new String(body, "UTF-8");
					System.out.println("msg1:" + msg);
					Thread.sleep(2000);
					int i = 1/0;
					channel.basicAck(envelope.getDeliveryTag(), false);
				} catch (Exception e) {
					System.out.println("异常了");
				} finally {
					//channel.basicAck(envelope.getDeliveryTag(), false);
				}
			}

		};
		// 监听队列,将自动应答关闭,使用手动应答
		boolean autoAck = false;
		channel.basicConsume(QUNUE_NAME, autoAck, consumer);
	}


消息持久化
当rabbitmq发生故障的时候,如果没有将声明的消息队列进行持久化声明,那么消息会丢失。声明消息队列时,可在参数中指明是否持久化,queueDeclare方法的第二个参数设置成true则表明持久化消息队列中的消息
在这里插入图片描述

channel.queueDeclare(QUNUE_NAME, true, false, false, null);

注意:如果是已经声明过的队列,使用queueDeclare的不同参数再次声明该队列的时候会报错,不允许使用不同的参数声明已经存在的队列,可以在后台将原有队列删除,或者重新定义新的队列。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值