RabbitMQ消息持久化

RabbitMQ基本概念 http://t.csdn.cn/SYzGG

rabbitMQ使用方式 http://t.csdn.cn/tZV5K

-----------------------------------------------------------------------------------------------

消息持久化:当 RabbitMQ 服务停掉以后,消息生产者发送过来的消息不丢失

实现方式:队列持久化,消息持久化、发布确认(同时使用达到最优的消息持久化)

工具类

public class RabbitMqUtils {
    /**
     * 获得获得信道channel
     * @return
     * @throws Exception
     */
    public static Channel getChannel() throws Exception{
        //创建一个连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.35.132");
        factory.setUsername("itcast");
        factory.setPassword("123321");
        Connection connection = factory.newConnection();
        return connection.createChannel();
    }
}

1、队列持久化

public static final String QUEUE_NAME = "ack_queue";

    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMqUtils.getChannel();
        // 声明队列
        // 队列持久化设置(true 为持久化,false 为默认不持久化)
        boolean durable = true;
        channel.queueDeclare(QUEUE_NAME, durable,false,false,null);
        // 发送消息
        // MessageProperties.PERSISTENT_TEXT_PLAIN 用来设置 消息持久化
        channel.basicPublish("",QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, "消息手动应答".getBytes(StandardCharsets.UTF_8));
        System.out.println("消息发送成功");
    }

2、消息持久化

  public static final String QUEUE_NAME = "ack_queue";

    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMqUtils.getChannel();
        // 声明队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        // 发送消息
        // MessageProperties.PERSISTENT_TEXT_PLAIN 用来设置 消息持久化
        channel.basicPublish("",QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, "消息手动应答".getBytes(StandardCharsets.UTF_8));
        System.out.println("消息发送成功");
    }

        将消息标记为持久化并不能完全保证不会丢失消息。尽管它告诉 RabbitMQ 将消息保存到磁盘,但是这里依然存在当消息刚准备存储在磁盘的时候 但是还没有存储完,消息还在缓存的一个间隔点。此时并没有真正写入磁盘。持久性保证并不强,进而需要引入发布确认

3、发布确认

3.1发布确认实现有三种 


public class ConfirmMessage {
    // 批量发消息的个数
    public static  final int MESSAGE_COUNT = 1000;

    public static void main(String[] args) throws Exception {
        // test1(); // 单个确认所有时间为:1364
        // test2();  //批量确认所有时间为:105
        test3();   // 异步批量确认所有时间为:74
    }

    
    
    public static  void test1() throws Exception {
        Channel channel = RabbitMqUtils.getChannel();
        // 开启发布确认
        channel.confirmSelect();
        // 声明一个队列
        channel.queueDeclare("singleConfirmQueue",true,false,false,null);
        Long start = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            // 发送消息
            channel.basicPublish("","singleConfirmQueue",null,"你好".getBytes());
            // 单个发布确认
            boolean b = channel.waitForConfirms();
            if (b) {
                System.out.println("消息发送成功");
            }else{
                System.out.println("消息发送失败");
            }
        }
        Long end = System.currentTimeMillis();
        System.out.println("单个确认所有时间为:"+(end-start));
    }


    
    
    public static  void test2() throws Exception {
        Channel channel = RabbitMqUtils.getChannel();
        // 开启发布确认
        channel.confirmSelect();
        // 声明一个队列
        channel.queueDeclare("singleConfirmQueue",true,false,false,null);
        Long start = System.currentTimeMillis();

        // 批量确认的长度
        int batchSize = 100;

        for (int i = 0; i < 1000; i++) {
            // 发送消息
            channel.basicPublish("","singleConfirmQueue",null,"你好".getBytes());

            // 达到100条确认一次
            if (i%batchSize == 0)
            {
                // 单个发布确认
                boolean b = channel.waitForConfirms();
                if (b) {
                    System.out.println("消息发送成功");
                }
            }
        }
        Long end = System.currentTimeMillis();
        System.out.println("批量确认所有时间为:"+(end-start));
    }

    
    
    
    //异步批量确认
    public static  void test3() throws Exception{
        Channel channel = RabbitMqUtils.getChannel();
        // 开启发布确认
        channel.confirmSelect();
        // 声明一个队列
        channel.queueDeclare("singleConfirmQueue",true,false,false,null);
        /**
         * 线程安全有序的一个哈希表,适用于高并发的情况
         * 1.轻松的将序号与消息进行关联
         * 2.轻松批量删除条目 只要给到序列号
         * 3.支持并发访问
         */
        ConcurrentSkipListMap outstandingConfirms = new ConcurrentSkipListMap<>();

        System.out.println("------------------------------监听器-------------------------------------------------");
        /**
         * 准备消息监听器,监听哪些消息成功,哪些消息失败
         */
        // 消息确认成功,回调函数
        ConfirmCallback ackCallback =( deliveryTag,  multiple)->{
            // 判断是否是批量
           if (multiple) {
               // 2、删除掉已经确认的消息,剩下的都是未确认的消息
               ConcurrentNavigableMap confirm = outstandingConfirms.headMap(deliveryTag);
               confirm.clear();
           }else {
               outstandingConfirms.remove(deliveryTag);
           }
            System.out.println("确认的消息"+deliveryTag);
        };
        // 消息确认失败,回调函数
        ConfirmCallback nackCallback = ( deliveryTag,  multiple)->{
            // 3、打印未确认的消息
            String s = outstandingConfirms.get(deliveryTag);
            System.out.println("未确认的消息的标记"+deliveryTag+"未确认的消息是:"+s);
        };
        // 监听是异步的
        channel.addConfirmListener(ackCallback,nackCallback);
        System.out.println("------------------------------监听器-------------------------------------------------");

        Long start = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            String message = "message"+ i;
            // 发送消息
            channel.basicPublish("","singleConfirmQueue",null,message.getBytes());
            // 1、记录所有要发送的消息
            outstandingConfirms.put(channel.getNextPublishSeqNo(),message);
        }
        Long end = System.currentTimeMillis();
        System.out.println("异步批量确认所有时间为:"+(end-start));
    }
}

你可能感兴趣的:(中间件,java-rabbitmq)