RabbitMQ学习七 RabbitMQ的可靠性

默认情况下,RabbitMQ会将接收到的信息保存在内存中以降低消息收发的延迟。这样做可能对导致两个问题:

  • 一旦MQ宕机,内存中的消息会丢失

  • 内存空间有限,当消费者故障或者处理速度慢时,会导致消息积压,再进来的消息,消息就无法进去队列,此时RabbitMQ会把队列的消息落到磁盘(page out),而在把消息落到磁盘的过程是阻塞的。

要解决上述两个问题,RabbitMQ给出了两个解决方案:数据持久化Lazy Queue

数据持久化是3.6之前提出的,3.6之后RabbitMQ又提出了Lazy Queue。

一、数据持久化

数据持久化可以包括三个方面:

交换机持久化:在创建交换机时,可以把交换机设置成Durable

队列持久化: 在创建队列时,可以把队列设置成Durable

消息持久化: 在发送消息时,DeliveryMode 选择2

开启生产者确认时,此时每秒只能接收600左右的消息,且消息在都在内存中。

@RequestMapping("/sendMessageConfirmRate")
    public String sendMessageConfirmRate(){

        Message message = MessageBuilder
                .withBody("hello".getBytes(StandardCharsets.UTF_8))
                .setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT)
                .build();
        for(int i=0;i<1000000;i++){
            rabbitTemplate.convertAndSend("simple_queue",message);
        }
        return "ok";
    }

 

关闭生产者确认时,速度会有明显提示,因此消息没有配置持久化,所以当内存总的队列满的时候,会发生paged out,此时RabbitMQ会把一部分消息临时转移到磁盘。在把消息从内存转移到磁盘的过程中,RabbitMQ会停止接收消息,因此会出现RabbitMQ暂停工作的情况。

 

从上图中也可以看到,当发送临时消息很快时,会造成Paged Out,当Paged Out发生时,会造成MQ无法接收消息。

 

把上述队列中的消息清空,测试持久化队列的测试。

@RequestMapping("/sendMessageConfirmRate")
    public String sendMessageConfirmRate(){

        Message message = MessageBuilder
                .withBody("hello".getBytes(StandardCharsets.UTF_8))
                .setDeliveryMode(MessageDeliveryMode.PERSISTENT)
                .build();
        for(int i=0;i<1000000;i++){
            rabbitTemplate.convertAndSend("simple_queue",message);
        }
        return "ok";
    }

 

二、Lazy Queue

从RabbitMQ的3.6.0版本开始就增加了Lazy Queue的概念,也就是惰性队列

惰性队列的特征如下:

  • 接收到消息后直接存入磁盘而非内存(内存中只保留最近的消息,默认2048条)

  • 只有在消费者需要消费消息时才会从磁盘中读取并加载到内存

  • 支持数百万条的消息存储。

在RabbitMQ 3.12版本之后, 所有队列都是Lazy Queue模式,无法更改。也就是从3.12之后不会存在纯内存的模式了。

 

控制台设置Lazy Queue

在控制台创建队列时,可以点击Lazy mode,此时就会给队列添加一个参数x-queue-mode值是lazy

java代码设置

 

/**
     * 声明一个简单的队列
     * @return
     */
    @Bean("lazyQueue")
    public Queue lazyQueue(){
        return QueueBuilder
                .durable("lazy.queue")
                .lazy()
                .build();
    }

或者在监听时声明

  @RabbitListener(queuesToDeclare = @Queue(
            name = "lazy.queue",
            durable = "true",
            arguments = @Argument(name = "x-queue-mode",value = "lazy")
    ))
    public void listenLazyQueue(String msg){
        System.out.println("消费消息"+msg);
    }

一百万消息实验

@RequestMapping("/sendMessageConfirmRate")
    public String sendMessageConfirmRate(){

        Message message = MessageBuilder
                .withBody("hello".getBytes(StandardCharsets.UTF_8))
                .setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT)
                .build();
        for(int i=0;i<1000000;i++){
            rabbitTemplate.convertAndSend("lazy.queue",message);
        }
        return "ok";
    }

 

posted @ 2024-01-21 17:27  阿瞒123  阅读(13)  评论(0编辑  收藏  举报