• RabbitMQ学习05--消息可靠性


    消息可靠性:

    1.如果消息已经到达了rabbitmq,但mq宕机了,消息并不会丢失。rabbitmq有持久化机制。

    2.消费者在消费消息时,没有执行完就宕机了,消息并不会从mq清除,消费者可以使用手动ack机制。

    3.生产者发送消息时由于网络问题,消息没有发送到rabbitmq,可以采用以下两种机制:事务操作,confirm操作。

    1、RabbitMQ事务(不推荐):

    事务可以保证消息100%传递,可以通过事务的回滚,后面定时再次发送当前消息。

    事务机制的缺点:效率低。加了事务要比正常速度低100倍。

    2、Confirm确认机制:

    Confirm机制是确保生产者将消息发送给了RabbitMQ的exchange。

    2.1 普通Confirm方式:

     1 package com.yas.confirm;
     2 
     3 import com.rabbitmq.client.Channel;
     4 import com.rabbitmq.client.Connection;
     5 import com.yas.config.RabbitMQClient;
     6 import org.junit.Test;
     7 
     8 public class Publisher {
     9     @Test
    10     public void publish() throws Exception {
    11         //1.获取连接对象
    12         Connection connection = RabbitMQClient.getConnection();
    13         //2.创建Channel
    14         Channel channel = connection.createChannel();
    15         //3.发布消息到exchange,同时指定路由规则
    16 
    17         //3.1 开启Confirm
    18         channel.confirmSelect();
    19 
    20         String msg = "Hello World";
    21         //参数1:指定exchange,使用空字符串,表示默认exchange。
    22         //参数2:指定路由规则,使用具体的队列名称。
    23         //参数3:指定传递的消息所携带的properties。
    24         //参数4:指定发布的具体消息,字节数组类型byte[]
    25         channel.basicPublish("", "HelloWorld", null, msg.getBytes());
    26         //注意:exchange是不会将消息持久化到本地的,Queue有持久化的功能。
    27 
    28         //判断消息发送是否成功
    29         if (channel.waitForConfirms()) {
    30             System.out.println("消息发送成功");
    31         }else{
    32             System.out.println("消息发送失败");
    33         }
    34 
    35         System.out.println("生产者发布消息成功");
    36         //4.释放资源
    37         channel.close();
    38         connection.close();
    39     }
    40 }

    2.2 批量Confirm方式:

     1 package com.yas.confirm;
     2 
     3 import com.rabbitmq.client.Channel;
     4 import com.rabbitmq.client.Connection;
     5 import com.yas.config.RabbitMQClient;
     6 import org.junit.Test;
     7 
     8 public class Publisher2 {
     9     @Test
    10     public void publish() throws Exception {
    11         //1.获取连接对象
    12         Connection connection = RabbitMQClient.getConnection();
    13         //2.创建Channel
    14         Channel channel = connection.createChannel();
    15         //3.发布消息到exchange,同时指定路由规则
    16 
    17         //3.1 开启Confirm
    18         channel.confirmSelect();
    19 
    20         String msg = "Hello World";
    21         //参数1:指定exchange,使用空字符串,表示默认exchange。
    22         //参数2:指定路由规则,使用具体的队列名称。
    23         //参数3:指定传递的消息所携带的properties。
    24         //参数4:指定发布的具体消息,字节数组类型byte[]
    25         for (int i = 0; i < 1000; i++) {
    26             msg = msg + i;
    27             channel.basicPublish("", "HelloWorld", null, msg.getBytes());
    28         }
    29         //注意:exchange是不会将消息持久化到本地的,Queue有持久化的功能。
    30 
    31         //判断消息发送是否成功
    32         //当发送的消息有一个失败时,就会全部失败
    33         channel.waitForConfirmsOrDie();
    34 
    35         System.out.println("生产者发布消息成功");
    36         //4.释放资源
    37         channel.close();
    38         connection.close();
    39     }
    40 }

    2.3 异步Confirm方式(推荐):

     1 package com.yas.confirm;
     2 
     3 import com.rabbitmq.client.Channel;
     4 import com.rabbitmq.client.ConfirmListener;
     5 import com.rabbitmq.client.Connection;
     6 import com.yas.config.RabbitMQClient;
     7 import org.junit.Test;
     8 
     9 import java.io.IOException;
    10 
    11 public class Publisher3 {
    12     @Test
    13     public void publish() throws Exception {
    14         //1.获取连接对象
    15         Connection connection = RabbitMQClient.getConnection();
    16         //2.创建Channel
    17         Channel channel = connection.createChannel();
    18         //3.发布消息到exchange,同时指定路由规则
    19 
    20         //3.1 开启Confirm
    21         channel.confirmSelect();
    22 
    23 
    24         //参数1:指定exchange,使用空字符串,表示默认exchange。
    25         //参数2:指定路由规则,使用具体的队列名称。
    26         //参数3:指定传递的消息所携带的properties。
    27         //参数4:指定发布的具体消息,字节数组类型byte[]
    28         for (int i = 0; i < 1000; i++) {
    29             String msg = "Hello World";
    30             msg = msg + i;
    31             channel.basicPublish("", "HelloWorld", null, msg.getBytes());
    32         }
    33         //注意:exchange是不会将消息持久化到本地的,Queue有持久化的功能。
    34 
    35         //判断消息发送是否成功
    36         //异步发送
    37         channel.addConfirmListener(new ConfirmListener() {
    38             @Override
    39             public void handleAck(long deliveryTag, boolean multiple) throws IOException {
    40                 System.out.println("消息发送成功,标识:" + deliveryTag + ",是否是批量:" + multiple);
    41             }
    42 
    43             @Override
    44             public void handleNack(long deliveryTag, boolean multiple) throws IOException {
    45                 System.out.println("消息发送失败,标识:" + deliveryTag + ",是否是批量:" + multiple);
    46             }
    47         });
    48 
    49         System.out.println("生产者发布消息成功");
    50 
    51         System.in.read();
    52         //4.释放资源
    53         channel.close();
    54         connection.close();
    55     }
    56 }

    3、Return机制:

    Return机制是确保在RabbitMQ内部,exchange将消息发送给queue。

    而且exchange是不能持久化消息的,queue才可以持久化,因此消息发送到queue才能保证不丢失。

    采用Return机制,监听消息是否从exchange发送到了queue。

    生产者代码:

     1 package com.yas.myreturn;
     2 
     3 import com.rabbitmq.client.*;
     4 import com.yas.config.RabbitMQClient;
     5 import org.junit.Test;
     6 
     7 import java.io.IOException;
     8 
     9 public class Publisher {
    10     @Test
    11     public void publish() throws Exception {
    12         //1.获取连接对象
    13         Connection connection = RabbitMQClient.getConnection();
    14         //2.创建Channel
    15         Channel channel = connection.createChannel();
    16 
    17         //3.1 开启Confirm
    18         channel.confirmSelect();
    19 
    20         //判断消息发送是否成功
    21         //异步发送
    22         channel.addConfirmListener(new ConfirmListener() {
    23             @Override
    24             public void handleAck(long deliveryTag, boolean multiple) throws IOException {
    25                 System.out.println("消息发送成功,标识:" + deliveryTag + ",是否是批量:" + multiple);
    26             }
    27 
    28             @Override
    29             public void handleNack(long deliveryTag, boolean multiple) throws IOException {
    30                 System.out.println("消息发送失败,标识:" + deliveryTag + ",是否是批量:" + multiple);
    31             }
    32         });
    33 
    34         //3.发布消息到exchange,同时指定路由规则
    35 
    36         //开启Return机制
    37         channel.addReturnListener(new ReturnListener() {
    38             //当消息没有送到queue时,才会执行
    39             @Override
    40             public void handleReturn(int replyCode, String replyText, String exchange, String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException {
    41                 System.out.println(new String(body, "UTF-8") + "没有送到Queue中");
    42             }
    43         });
    44 
    45         //参数1:指定exchange,使用空字符串,表示默认exchange。
    46         //参数2:指定路由规则,使用具体的队列名称。
    47         //参数3:指定传递的消息所携带的properties。
    48         //参数4:指定发布的具体消息,字节数组类型byte[]
    49 //        channel.basicPublish("", "HelloWorld", null, msg.getBytes());
    50 
    51         //使用带return机制的发布,mandatory:true
    52         for (int i = 0; i < 1000; i++) {
    53             String msg = "Hello World";
    54             msg = msg + i;
    55             channel.basicPublish("", "HelloWorld",true, null, msg.getBytes());
    56         }
    57 
    58         //注意:exchange是不会将消息持久化到本地的,Queue有持久化的功能。
    59 
    60         System.out.println("生产者发布消息成功");
    61         System.in.read();
    62         //4.释放资源
    63         channel.close();
    64         connection.close();
    65     }
    66 }

    消费者代码:

     1 package com.yas.myreturn;
     2 
     3 import com.rabbitmq.client.*;
     4 import com.yas.config.RabbitMQClient;
     5 import org.junit.Test;
     6 
     7 import java.io.IOException;
     8 
     9 public class Consumer {
    10     @Test
    11     public void consume() throws  Exception{
    12         //1.获取连接对象
    13         Connection connection = RabbitMQClient.getConnection();
    14         //2.创建channel
    15         Channel channel = connection.createChannel();
    16         //3.生命队列-Hello World
    17         //参数1:queue,队列名称
    18         //参数2:durable,当前队列是否需要持久化
    19         //参数3:exclusive,是否排外
    20         //      影响1:当connection.close()时,当前队列会被自动删除
    21         //      影响2:当前队列只能被一个消费者消费
    22         //参数4:autoDelete,如果这个队列没有消费者消费,队列自动删除
    23         //参数5:arguments,指定当前队列的其他信息
    24         channel.queueDeclare("HelloWorld",true,false,false,null);
    25         //4.开启监听Queue
    26         DefaultConsumer consumer = new DefaultConsumer(channel){
    27             @Override
    28             public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
    29                 //super.handleDelivery(consumerTag, envelope, properties, body);
    30                 System.out.println("接受到消息:" + new String(body,"UTF-8"));
    31             }
    32         };
    33         //参数1:queue,指定消费哪个队列
    34         //参数2:deliverCallback,指定是否自动ACK,(true表示,接受到消息后,会立即通知RabbitMQ)
    35         //参数3:consumer,指定消费回调
    36         channel.basicConsume("HelloWorld",true,consumer);
    37         System.out.println("消费者开始监听队列");
    38         System.in.read();
    39         //5/释放资源
    40         channel.close();
    41         connection.close();
    42     }
    43 }
  • 相关阅读:
    Consul注销实例
    sql优化基础篇
    linux下执行java类(运行java定时器)
    ExecutorService 的理解与使用
    精度计算的方法
    内部类详解
    接口的作用
    面向对象之继承和组合浅谈
    构造器前篇
    教师编制考试数据分析
  • 原文地址:https://www.cnblogs.com/asenyang/p/15502023.html
Copyright © 2020-2023  润新知