RabbitMQ的ack与nack

     在消息中间件的使用中,我们特别在意的一件事就是保证消息不会丢失并且被准确消费,昨天简单写了一个消费者来观察消息的消费情况,现把研究结果跟大家分享一下。首先先看一个方法:

     

connection = factory.newConnection();
			
			final Channel channel = connection.createChannel();
			channel.queueDeclare("队列名", true, false, false, null);
			
			//第二个参数设为true为自动应答,false为手动ack
			channel.basicConsume("队列名", true, new DefaultConsumer(channel){
				  @Override
			        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
					   try {
						    Thread.sleep(10000);
						    System.out.println(new String(body, "UTF-8"));
							//模拟异常
							int i = 1/0;
							//手动ack
							//channel.basicAck(envelope.getDeliveryTag(), false); 
						} catch (Exception e) {
							
							//重新放入队列
							//channel.basicNack(envelope.getDeliveryTag(), false, true);
							//抛弃此条消息
							//channel.basicNack(envelope.getDeliveryTag(), false, false);
							e.printStackTrace();
	
						}finally {
							
						}
			            
			        }
			});
     这只是消费端的一段代码,不过它已经能展现出消息是怎么消费的了,handleDelivery 方法是回调方法,如果队列中有消息就会这行这个方法,参数中的body 就是消息内容。  channel.basicConsume 方法中第二个参数为boolean 类型,意思是消息的ack 需要自动(true)还是手动(false).

     首先在ack机制为自动的情况下,不管 try 中有没有异常,消息管理界面上队列里的消息都被消费了,没有了(ready和unacked状态栏都没有了),下面是管理界面, 队列中的未被消费的消息有多少条都会在ready状态栏下,分发到消费端后,消费端没有回发ack的消息会在unacked状态栏中。

RabbitMQ的ack与nack_第1张图片

     现在改为设置成手动ack应答(channel.basicAck方法),这样做的目的是保证消息在正确消费后给回馈,说明我正确消费了。这时队列就可以把这条消息删除了,如果消费端接收了消息,但是没有给返回ack应答,那么这条消息会继续存在unacked状态下,占据队列的空间,等到空间满了,就会出现接下来的消息不能被消费的情况。

     那么现在问题又来了,正确的消息被ack 了,那么在消费过程中有异常了怎么办,这条消费肯定就不能返回ack应答了,这时就需要channel.basicNack方法了,这个方法解决了消费异常情况下该条消息怎么处理,有两种办法:第一,这条消息重新放回队列重新消费,第二,抛弃此条消息。那么具体使用哪个方法,这种情况下,建议捕捉异常类型,判断是哪种异常,再做具体处理。

你可能感兴趣的:(消息中间件)