【参考】RabbitMQ使用场景练习:消息确认机制(十一)

  • 消息确认机制

RabbitMQ提供了transaction、confirm两种消息确认机制。transaction即事务机制,手动提交和回滚;confirm机制提供了Confirmlistener和waitForConfirms两种方式。confirm机制效率明显会高于transaction机制,但后者的优势在于强一致性。如果没有特别的要求,建议使用conrim机制。 

1、从实验来看,消息的确认机制只是确认publisher发送消息到broker,由broker进行应答,不能确认消息是否有效消费。 
2、而为了确认消息是否被发送给queue,应该在发送消息中启用参数mandatory=true,使用ReturnListener接收未被发送成功的消息。 
3、接下来就需要确认消息是否被有效消费。publisher端目前并没有提供监听事件,但提供了应答机制来保证消息被成功消费,应答方式: 
   basicAck:成功消费,消息从队列中删除 
   basicNack:requeue=true,消息重新进入队列,false被删除 
   basicReject:等同于basicNack 
   basicRecover:消息重入队列,requeue=true,发送给新的consumer,false发送给相同的consumer 

 

 

  • 应答模式之transaction机制

需要手动提交和回滚,执行txCommit,消息才会转发给队列进入ready状态;执行txRollback,消息被取消 

 

 

 

Java代码  收藏代码

  1. package com.demo.mq.rabbitmq.example11;  
  2. import java.io.IOException;  
  3. import java.io.Serializable;  
  4. import org.apache.commons.lang3.SerializationUtils;  
  5. import com.demo.mq.rabbitmq.MqManager;  
  6. import com.rabbitmq.client.AMQP;  
  7. import com.rabbitmq.client.Channel;  
  8. import com.rabbitmq.client.Connection;  
  9. import com.rabbitmq.client.DefaultConsumer;  
  10. import com.rabbitmq.client.Envelope;  
  11.   
  12. /** 
  13.  * 应答模式之transaction机制 
  14.  * @author sheungxin 
  15.  * 
  16.  */  
  17. public class TxDemo {  
  18.     private static String exchange_name="";  
  19.     private static String queue_name="tx_queue";  
  20.       
  21.     /** 
  22.      * transaction机制发送消息,事务机制:手动提交和回滚 
  23.      * 执行txCommit,消息才会转发给队列进入ready状态 
  24.      * 执行txRollback,消息被取消 
  25.      * @param mes 
  26.      * @throws Exception 
  27.      */  
  28.     public static void txSend(Serializable mes) throws Exception{  
  29.         Connection conn=MqManager.newConnection();  
  30.         Channel channel=conn.createChannel();  
  31.         //开启transaction机制  
  32.         channel.txSelect();  
  33.         channel.queueDeclare(queue_name,false,false,true,null);  
  34.         for(int i=0;i<10;i++){  
  35.             try{  
  36.                 channel.basicPublish(exchange_name, queue_name, null, SerializationUtils.serialize(mes.toString()+i));  
  37.                 //do something  
  38. //              int n=5/0;//试验消息回滚  
  39.                 channel.txCommit();//提交消息  
  40.                 System.out.println("发布消息"+mes.toString()+i);  
  41.             }catch(Exception e){  
  42.                 channel.txRollback();//异常,取消消息  
  43.                 System.out.println("回滚消息"+mes.toString()+i);  
  44.             }  
  45.         }  
  46.     }  
  47.   
  48.     /** 
  49.      * transaction机制接收消息,事务机制:手动提交和回滚 
  50.      * 消费者需要执行basicAck,并txCommit(自动应答模式自动处理,本例中采用手动应答模式) 
  51.      * @throws Exception 
  52.      */  
  53.     public static void txRecv() throws Exception{  
  54.         Connection conn=MqManager.newConnection();  
  55.         Channel channel=conn.createChannel();  
  56.         //开启transaction机制  
  57.         channel.txSelect();  
  58.         channel.queueDeclare(queue_name,false,false,true,null);  
  59.         //关闭自动应答模式(自动应答模式不需要ack、txCommit),需要手动basicAck,并执行txCommit  
  60.         channel.basicConsume(queue_name, falsenew DefaultConsumer(channel){  
  61.             @Override  
  62.             public void handleDelivery(String consumerTag,Envelope envelope,AMQP.BasicProperties properties,byte[] body) throws IOException{  
  63.                 String mes=SerializationUtils.deserialize(body);  
  64.                 System.out.println("tx Received :'"+mes+"' done");  
  65.                 channel.basicAck(envelope.getDeliveryTag(), false);  
  66.                 channel.txCommit();  
  67.                   
  68.             }  
  69.         });  
  70.     }  
  71.       
  72.     public static void main(String[] args) throws Exception {  
  73.         txSend("hello world!");  
  74.         txRecv();  
  75.     }  
  76. }  

 

  • 应答模式之confirm机制

1、确认publisher发送消息到broker,由broker进行应答(不能确认是否被有效消费) 
2、confirmSelect,进入confirm消息确认模式,确认方式:1、异步ConfirmListener;2、同步waitForConfirms 
3、ConfirmListener、waitForConfirms均需要配合confirm机制使用 
4、暂时未弄明白confirm机制在consumer的应用,ConfirmListener在consumer中无效 
5、basicNack、basicReject:参数requeue=true时,消息会重新进入队列 
6、autoDelete队列在消费者关闭后不管是否还有未处理的消息都会关闭掉 

 

 

Java代码  收藏代码

  1. package com.demo.mq.rabbitmq.example11;  
  2. import java.io.IOException;  
  3. import java.io.Serializable;  
  4. import org.apache.commons.lang3.SerializationUtils;  
  5. import com.demo.mq.rabbitmq.MqManager;  
  6. import com.rabbitmq.client.Channel;  
  7. import com.rabbitmq.client.ConfirmListener;  
  8. import com.rabbitmq.client.Connection;  
  9.   
  10. /** 
  11.  * 应答模式之confirm机制:消息发送 
  12.  * @author sheungxin 
  13.  * 
  14.  */  
  15. public class ConfirmSend {  
  16.     private static String exchange_name="";  
  17.     private static String queue_name="tx_queue";  
  18.       
  19.     /** 
  20.      * confirm机制:确认publisher发送消息到broker,由broker进行应答(不能确认是否被有效消费) 
  21.      * confirmSelect,进入confirm消息确认模式,确认方式:1、异步ConfirmListener;2、同步waitForConfirms 
  22.      * ConfirmListener、waitForConfirms均需要配合confirm机制使用 
  23.      * @param mes 
  24.      * @throws Exception 
  25.      */  
  26.     public static void txSend(Serializable mes) throws Exception{  
  27.         Connection conn=MqManager.newConnection();  
  28.         Channel channel=conn.createChannel();  
  29.         //开启transaction机制  
  30.         channel.confirmSelect();  
  31.         channel.queueDeclare(queue_name,false,false,true,null);  
  32.         //异步实现发送消息的确认(此部分的消息确认是指发送消息到队列,并非确认消息的有效消费)  
  33.         channel.addConfirmListener(new ConfirmListener() {  
  34.               
  35.             @Override  
  36.             public void handleNack(long deliveryTag, boolean multiple)  
  37.                     throws IOException {  
  38.                 //multiple:测试发现multiple随机true或false,原因未知  
  39.                 System.out.println("Nack deliveryTag:"+deliveryTag+",multiple:"+multiple);  
  40.             }  
  41.               
  42.             @Override  
  43.             public void handleAck(long deliveryTag, boolean multiple)  
  44.                     throws IOException {  
  45.                 System.out.println("Ack deliveryTag:"+deliveryTag+",multiple:"+multiple);  
  46.             }  
  47.         });  
  48.         for(int i=0;i<10;i++){  
  49.             channel.basicPublish(exchange_name, queue_name, null, SerializationUtils.serialize(mes.toString()+i));  
  50.         }  
  51. //      channel.waitForConfirms();//同步实现发送消息的确认  
  52.         System.out.println("-----------");  
  53.         channel.close();  
  54.         conn.close();  
  55.     }  
  56.       
  57.     public static void main(String[] args) throws Exception {  
  58.         txSend("hello world!");  
  59.     }  
  60. }  

 

Java代码  收藏代码

  1. package com.demo.mq.rabbitmq.example11;  
  2. import java.io.IOException;  
  3. import org.apache.commons.lang3.SerializationUtils;  
  4. import com.demo.mq.rabbitmq.MqManager;  
  5. import com.rabbitmq.client.AMQP;  
  6. import com.rabbitmq.client.Channel;  
  7. import com.rabbitmq.client.Connection;  
  8. import com.rabbitmq.client.DefaultConsumer;  
  9. import com.rabbitmq.client.Envelope;  
  10.   
  11. /** 
  12.  * 应答模式之confirm机制:消息接收 
  13.  * @author sheungxin 
  14.  * 
  15.  */  
  16. public class ConfirmRecv {  
  17.     private static String queue_name="tx_queue";  
  18.   
  19.     /** 
  20.      * confirm机制:暂时未弄明白confirm机制在consumer的应用,ConfirmListener在consumer中无效 
  21.      * basicNack、basicReject:参数requeue=true时,消息会重新进入队列 
  22.      * autoDelete队列在消费者关闭后不管是否还有未处理的消息都会关闭掉 
  23.      * @throws Exception 
  24.      */  
  25.     public static void txRecv() throws Exception{  
  26.         Connection conn=MqManager.newConnection();  
  27.         Channel channel=conn.createChannel();  
  28.         //开启transaction机制  
  29. //      channel.confirmSelect();  
  30.         //autoDelete,true只要被消息  
  31.         channel.queueDeclare(queue_name,false,false,true,null);  
  32.         //关闭自动应答模式  
  33.         channel.basicConsume(queue_name, falsenew DefaultConsumer(channel){  
  34.             @Override  
  35.             public void handleDelivery(String consumerTag,Envelope envelope,AMQP.BasicProperties properties,byte[] body) throws IOException{  
  36.                 String mes=SerializationUtils.deserialize(body);  
  37.                 //multiple批量提交,true提交小于参数中tag消息  
  38.                 long n=envelope.getDeliveryTag()%3;  
  39.                 if(n==0){  
  40.                     channel.basicAck(envelope.getDeliveryTag(), false);  
  41.                 }else if(n==1){  
  42.                     //requeue,true重新进入队列  
  43.                     channel.basicNack(envelope.getDeliveryTag(), falsetrue);  
  44.                 }else{  
  45.                     //requeue,true重新进入队列,与basicNack差异缺少multiple参数  
  46.                     channel.basicReject(envelope.getDeliveryTag(), true);  
  47.                 }  
  48.                 try {  
  49.                     Thread.sleep(2*1000);  
  50.                 } catch (InterruptedException e) {  
  51.                     e.printStackTrace();  
  52.                 }  
  53.                 System.out.println((n==0?"Ack":n==1?"Nack":"Reject")+" mes :'"+mes+"' done");  
  54.             }  
  55.         });  
  56.     }  
  57.       
  58.     public static void main(String[] args) throws Exception {  
  59.         txRecv();  
  60.     }  
  61. }  
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值