rabbitmq 消息确认机制

本文介绍了RabbitMQ的消息确认机制,包括生产端的transaction和confirm两种方式,以及消费端的确认过程。在测试环境中,confirm机制的性能优于transaction。当消费者消费消息但未ack时,消息状态为unacked,如果消费者关闭,未ack的消息会重新变为ready。消费者确认消息后,MQ才会删除消息。未确认的消息在消费者关闭后会被重新发送给其他消费者。代码示例中展示了基本的ack操作,批量ack并未显著提高性能。

rabbitmq的消息确认机制分两部分

一部分是生产端,一部分是消费端

以下都是经过本人亲测得出的结论

环境版本:

RabbitMQ 3.6.3, Erlang 19.0  rabbitmq-java-client-bin-3.6.3


生产端

有两种选择,transaction   和   confirm。

transaction机制

                      //transaction 机制  
			channel.txSelect();
			
			String msg = "msg  test !!!";
			for(int i=0;i<10000;i++){
				msg = i+" : msg  test !!!";
				channel.basicPublish(EXCHAGE, QUEUE_NAME,null,msg.getBytes());
				 System.out.println("publish msg "+msg);
				 if (i>0&&i%100==0){
					 //批量提交
				 	channel.txCommit();
				 }
					 
			} // 若出现异常 进行 channel.txRollback(),对相应批次的msg进行重发或记录
                       channel.txCommit();




confirm机制

// confirm  机制 异步 通过注册listener,实现异步ack,提高性能  
            channel.confirmSelect();  
            
            // 可以考虑将要发送到MQ的msg记录到SortedSet(TreeSet)中  
			channel.addConfirmListener(new ConfirmListener() {  
				    @Override  
				    public void handleAck(long deliveryTag, boolean multiple) throws IOException {  
				         System.out.println("+++++++++++++handleAck   deliveryTag: " + deliveryTag + ", multiple: " + multiple);  
				         if (multiple) {  
                              // sortedSet.headSet(deliveryTag + 1).clear();  
                         } else {  
                             // sortedSet.remove(deliveryTag);  
                         }  
				    }  
				    @Override  
				    public void handleNack(long deliveryTag, boolean multiple) throws IOException {  
				           System.out.println("------------handleNack   deliveryTag: " + deliveryTag + ", multiple: " + multiple);  
				           if (multiple) {  
                            // sortedSet.headSet(deliveryTag + 1) toDo    进行重新发送,或记录下来,后续再统一发送;  
                           } else {  
                            // sortedSet.first();  进行重新发送,或记录下来,后续再统一发送;  
                           }  
				    }   
		   }); 




                  // confirm  机制  同步 
			channel.confirmSelect();
			
			String msg = "msg  test !!!";
			for(int i=0;i<10000;i++){
				msg = i+" : msg  test !!!";
				channel.basicPublish(EXCHAGE, QUEUE_NAME,null,msg.getBytes());
				 System.out.println("publish msg "+msg);
				 //此处的 if 是为了实现批量confirm 能比较好的提高性能
				 if (i>0&&i%100==0){
					 if(channel.waitForConfirms()){
						 System.out.println("success publish msg " + (i-100)+" to "+i);
					 }else{
						 System.out.println("failed publish msg " + (i-100)+" to "+i);
						 i-=100;//此处-100是为了重发,也可以先记录下,之后再进行重发
					 }
				 }
			}

confirm  的性能要好于transaction



消费端

首先通过producer往mq中放置了10个msg


然后通过debug断点方式consumer进行消费,但是先不ack,如下

可以看到已经被消费掉了,但是状态还是unacked


后面若一直不执行basicAck,则状态就一直保持不变

再如果我将consumer关掉,则unacked的msg又回到了ready。

这就是consumer的确认机制,来保证把消息真正的处理完后,告诉MQ,让其删除。

若consumer没有ack,则MQ就不会删除,即使consumer死掉,MQ又会把消息发给其他consumer(如果有其他consumer的话)


如下我将consumer干掉,MQ中的消息变成了


我再启动consumer,并进行2个msg的ack后,结果如下图


下图是10msg的ack后



代码中的关键的两处如下,其中注释的两行

private static void revieve() {
		try {
			ConnectionFactory factory = new ConnectionFactory();
			factory.setHost(HOST);
			factory.setUsername(USERNAME);
			factory.setPassword(PASSWORD);
			Connection connection = factory.newConnection();
			final Channel channel = connection.createChannel();

			channel.queueDeclare(QUEUE_NAME, false, false, false, null);

			QueueingConsumer consumer = new QueueingConsumer(channel);
			//消费消息,其中的false表示需要后面显示的调用basicAck,告诉MQ将msg删除
			channel.basicConsume(QUEUE_NAME, false, consumer);
			while (true) {
				QueueingConsumer.Delivery delivery = consumer.nextDelivery();

				String msg = new String(delivery.getBody());

				System.out.println("recieve " + msg);
				//显示发送ack,只有在前面进行启用显示发送ack机制后才奏效。 false代表是否multiple
				channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
				
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

上面代码basicAck中的第二个参数若是true,则表示小于等于这个tag的全部发ack,类似于批量ack。本以为这个功能能够提高ack的性能,类似于批量。

但结果不是很明显,我设的批量值是100,我的ack能达到1000/s 左右。不知是我批量值设置问题,还是本身性能就这样。




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值