1.声明

当前内容用于本人学习和复习之用,当前内容主要为消息确认机制的使用和理解

内容来源:RabbitMQ的消息确认消费者确认和发布者确认

2.官方的Message Acknowledgements介绍

  1. Consumer applications – that is, applications that receive and process messages – may occasionally fail to process individual messages or will sometimes just crash. There is also the possibility of network issues causing problems. This raises a question: when should the broker remove messages from queues? The AMQP 0-9-1 specification gives consumers control over this. There are two acknowledgement modes:
    1.1 After broker sends a message to an application (using either basic.deliver or basic.get-ok method).
    1.2. After the application sends back an acknowledgement (using the basic.ack method).

消费者程序,有的时候在接收和处理消息的时候有可能出现处理消息失败,或者有的时候直接崩溃掉、有的时候是网络的原因导致的。这就会有一个问题,什么时候代理者会把消息从队列中移除掉?这个AMQP协议提供了消费者控制它,主要有两种方法进行确认控制:

1.在代理者发送消息到一个程序后(使用basic.deliver或者basic.get-ok方法)

2.在这个程序返回一个确认回调(使用basic.ack方法)

分析上面发现

当前内容主要用于处理消息确认的,防止消息消费失败的情况处理,可以使用主动方式:代理者直接请求消费者,询问是否处理成功。也可以使用消费者主动向代理者发送消费成功的标记

The former choice is called the automatic acknowledgement model, while the latter is called the explicit acknowledgement model. With the explicit model the application chooses when it is time to send an acknowledgement. It can be right after receiving a message, or after persisting it to a data store before processing, or after fully processing the message (for example, successfully fetching a Web page, processing and storing it into some persistent data store).

If a consumer dies without sending an acknowledgement, the broker will redeliver it to another consumer or, if none are available at the time, the broker will wait until at least one consumer is registered for the same queue before attempting redelivery.

前者是自动成功模式,后者是显示确认模式。使用显示确认中需要选择什么时候进行发送一个确认。或者在将消息持久保存到数据存储之前(在处理之前)或在完全处理消息之后(例如,成功获取Web页,将其处理并将其存储到某个持久数据存储中)之后。

如果一个消费者死亡但是没有发送一个确认,那么这个代理者将会重新将这个消息发送给另外一个消费者,如果没有任何一个可以发送的消费者,bane这个代理者将会等待直到一个消费者被注册在这个队列中,然后在发送消息

分析发现

显示成功模式就是消费者手动确认已近成功,并且需要在自己选择时间发送,但是会有一个问题,那就是执行完成但是却死亡,这样就会出现消息的重复发送(和消息的重复消费)

由于自动确认是代理者自动确认并且当前的autoAck设置为true的时候自动开启,所以不需要测试

3.实现显示确认模式

1.创建一个测试的exchange并使用类型为topic

mq 消费者通知信息已被消费 python mq如何确认消息被消费_发送消息

2.创建一个hello队列

mq 消费者通知信息已被消费 python mq如何确认消息被消费_重启_02

3.编写代码参考:RabbitMQ官方的消息确认机制

public class MessageAcknowledgementsTest {
	private static final String queueName = "hello";

	public static void main(String[] args) {
		RabbitMqUtils mqUtils = new RabbitMqUtils();
		Connection connection = null;
		try {
			connection = mqUtils.getConnection();
			final Channel chan = connection.createChannel();
			// 回调方式应答,就是服务器发送消息,然后直接在函数内应答
			chan.queueDeclare(queueName, true, false, false, null);
			chan.basicConsume("hello", false, "a-consumer-tag", new DefaultConsumer(chan) {
				@Override
				public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
						byte[] body) throws IOException {
					System.out.println("消费者开始处理消息===>" + new String(body, "utf-8"));
					// 获取传递标记
					long deliveryTag = envelope.getDeliveryTag();
					// 应用程序发送回确认之后(使用basic.ack方法),队列已经消费成功
					chan.basicAck(deliveryTag, false);
					System.out.println("消息执行成功===>通知服务器消费成功");
				}
			});
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

启动后结果

mq 消费者通知信息已被消费 python mq如何确认消息被消费_System_03


开始发送消息(使用ui界面发送)

mq 消费者通知信息已被消费 python mq如何确认消息被消费_System_04


控制台结果

mq 消费者通知信息已被消费 python mq如何确认消息被消费_System_05


queue的情况

mq 消费者通知信息已被消费 python mq如何确认消息被消费_System_06

从这里看基本上和前面的没有区别,但是只要我们修改了一点点就会出现不同的情况

直接注释掉//chan.basicAck(deliveryTag, false);

然后重启消费者,再次从ui界面发送消息就会发现问题

mq 消费者通知信息已被消费 python mq如何确认消息被消费_System_07


mq 消费者通知信息已被消费 python mq如何确认消息被消费_System_08


最后重启该消费者又发现

mq 消费者通知信息已被消费 python mq如何确认消息被消费_System_09

这就是出现了重复消费的问题,无论客户端重启多少次,但是实际上代理者并没有将该消费的消息从queue中删除,这就是显示确认模式的时候具有的问题(一定记得ack否者认为消息没有消费成功)

4.分析上面的代码

1.如果需要使用的时候必须手动将当前的basicConsume的autoAck设定为false(表示关闭自动确认模式)

2.显示确认的时候必须获取当前的信封中的deliveryTag,然后通过basicAck方法进行应答操作

3.所以一般的情况下,我们只要找到autoAck的方法,就表示支持手动和自动确认

于是本人发现了这个chan.basicGet

5.测试chan.basicGet方式实现一条条数据的确认

GetResponse basicGet = chan.basicGet("hello", false);
	System.out.println("消费者消费==>" + new String(basicGet.getBody(), "utf-8"));
	Envelope envelope = basicGet.getEnvelope();
	long deliveryTag = envelope.getDeliveryTag();
	chan.basicAck(deliveryTag, false);

ui结果

mq 消费者通知信息已被消费 python mq如何确认消息被消费_重启_10

测试成功

6.总结

1.因为消息在消费的时候可能出现一些意外,比如突然断电、网络故障等问题,所以需要需要消息确认

2.消息确认分为两种:自动确认只要autoAck设置为true即可自动完成,显示确认需要将autoAck设置为false,并且需要使用basicAck进行显示提交确认(参数为false表示只确认这一条,设置为true则确认多条)

3.消息确认是为了消息队列的高可用和防止消息的重复消费而设定的

以上纯属个人见解,如有问题请联系本人!