一、持久化机制介绍

rabbitTemplate持久化消息 rabbitmq持久化原理_spring boot

01、RibbitMQ持久化
持久化就把信息写入到磁盘的过程。

02、RabbitMQ持久化消息
把消息默认放在内存中是为了加快传输和消费的速度,存入磁盘是保证消息数据的持久化。

03、RabbitMQ非持久化消息
非持久消息:是指当内存不够用的时候,会把消息和数据转移到磁盘,但是重启以后非持久化队列消息就丢失。

二、RabbitMQ持久化分类

RabbitMQ的持久化队列分为:
1:队列持久化
2:消息持久化
3:交换机持久化
不论是持久化的消息还是非持久化的消息都可以写入到磁盘中,只不过非持久的是等内存不足的情况下才会被写入到磁盘中。

2.1 队列持久化

RabbitMQ队列持久化的代码实现
队列的持久化是定义队列时的durable参数来实现的,Durable为true时,队列才会持久化。

// 参数1:名字  
// 参数2:是否持久化,
// 参数3:独du占的queue, 
// 参数4:不使用时是否自动删除,
// 参数5:其他参数
channel.queueDeclare(queueName,true,false,false,null);

若整合springboot的话:

@Bean
    public Queue directTTLQueue() {
        /*
         *  如果队列不存在,则会创建
         *  Rabbitmq不允许创建两个相同的队列名称,否则会报错。
         *
         *  @params1: queue 队列的名称
         *  @params2: durable 队列是否持久化
         *  @params3: exclusive 是否排他,即是否私有的,如果为true,会对当前队列加锁,其他的通道不能访问,并且连接自动关闭
         *  @params4: autoDelete 是否自动删除,当最后一个消费者断开连接之后是否自动删除消息。
         *  @params5: arguments 可以设置队列附加参数,设置队列的有效期,消息的最大长度,队列的消息生命周期等等。
         * */
        Map<String,Object> args2 = new HashMap<>();
        args2.put("x-message-ttl",5000);
        return new Queue("ttl.direct.queue", true, false, false, args2);
    }

其中参数2:设置为true,就代表的是持久化的含义。即durable=true。持久化的队列在web控制台中有一个D 的标记

rabbitTemplate持久化消息 rabbitmq持久化原理_rabbitmq_02

2.2 消息持久化

消息持久化是通过消息的属性deliveryMode来设置是否持久化,在发送消息时通过basicPublish的参数传入。

// 参数1:交换机的名字
// 参数2:队列或者路由key
// 参数3:是否进行消息持久化
// 参数4:发送消息的内容
channel.basicPublish(exchangeName, routingKey1, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());xxxxxxxxxx // 参数1:交换机的名字// 参数2:队列或者路由key// 参数3:是否进行消息持久化// 参数4:发送消息的内容channel.basicPublish(exchangeName, routingKey1, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());// 参数1:交换机的名字// 参数2:队列或者路由key// 参数3:是否进行消息持久化// 参数4:发送消息的内容channel.basicPublish(exchangeName, routingKey1, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());

整合springboot的话:

MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().setExpiration("5000");
                message.getMessageProperties().setContentEncoding("UTF-8");
                message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                return message;
            }
        };
        rabbitTemplate.convertAndSend(exchangeName, routingKey, orderNumer,messagePostProcessor);

2.3 交换机持久化

和队列一样,交换机也需要在定义的时候设置持久化的标识,否则在rabbit-server服务重启以后将丢失。

// 参数1:交换机的名字
// 参数2:交换机的类型,topic/direct/fanout/headers
// 参数3:是否持久化
channel.exchangeDeclare(exchangeName,exchangeType,true);

整合springboot使用:

@Bean
    public DirectExchange directTTLOrderExchange() {
        //参数一:名字
        //参数二:是否持久化
        //参数三:是否自动删除(没有消费者消费时,自动移除)
        return new DirectExchange("ttl_order_exchange", true, false);
    }

三、RabbitMQ内存磁盘的监控

3.1 RabbitMQ的内存警告

当内存使用超过配置的阈值或者磁盘空间剩余空间对于配置的阈值时,RabbitMQ会暂时阻塞客户端的连接,并且停止接收从客户端发来的消息,以此避免服务器的崩溃,客户端与服务端的心态检测机制也会失效。

如下图:

rabbitTemplate持久化消息 rabbitmq持久化原理_rabbitmq_03


当出现blocking或blocked话说明到达了阈值和以及高负荷运行了。

3.2 RabbitMQ的内存控制

参考帮助文档:https://www.rabbitmq.com/configure.html
当出现警告的时候,可以通过配置去修改和调整

3.2.1 命令的方式

rabbitmqctl set_vm_memory_high_watermark <fraction>rabbitmqctl set_vm_memory_high_watermark absolute 50MB

raction/value 为内存阈值。默认情况是:0.4/2GB,代表的含义是:当RabbitMQ的内存超过40%时,就会产生警告并且阻塞所有生产者的连接。通过此命令修改阈值在Broker重启以后将会失效,通过修改配置文件方式设置的阈值则不会随着重启而消失,但修改了配置文件一样要重启broker才会生效。

测试分析:
执行命令:

rabbitmqctl set_vm_memory_high_watermark absolute 50MB

将最大内存设为50MB,出现飘红

rabbitTemplate持久化消息 rabbitmq持久化原理_spring boot_04


队列出现block

rabbitTemplate持久化消息 rabbitmq持久化原理_java_05

3.2.2 配置文件方式 rabbitmq.conf

当前配置文件:/etc/rabbitmq/rabbitmq.conf

#默认
#vm_memory_high_watermark.relative = 0.4
# 使用relative相对值进行设置fraction,建议取值在04~0.7之间,不建议超过0.7.
vm_memory_high_watermark.relative = 0.6
# 使用absolute的绝对值的方式,但是是KB,MB,GB对应的命令如下
vm_memory_high_watermark.absolute = 2GB

3.3 RabbitMQ的内存换页

在某个Broker节点及内存阻塞生产者之前,它会尝试将队列中的消息换页到磁盘以释放内存空间,持久化和非持久化的消息都会写入磁盘中,其中持久化的消息本身就在磁盘中有一个副本,所以在转移的过程中持久化的消息会先从内存中清除掉。

默认情况下,内存到达的阈值是50%时就会换页处理。
也就是说,在默认情况下该内存的阈值是0.4的情况下,当内存超过0.4*0.5=0.2时,会进行换页动作。

比如有1000MB内存,当内存的使用率达到了400MB,已经达到了极限,但是因为配置的换页内存0.5,这个时候会在达到极限400mb之前,会把内存中的200MB进行转移到磁盘中。从而达到稳健的运行。

可以通过设置 vm_memory_high_watermark_paging_ratio 来进行调整

vm_memory_high_watermark.relative = 0.4
vm_memory_high_watermark_paging_ratio = 0.7(设置小于1的值)

为什么设置小于1,以为你如果你设置为1的阈值。内存都已经达到了极限了。你在去换页意义不是很大了。

3.4 RabbitMQ的磁盘预警

当磁盘的剩余空间低于确定的阈值时,RabbitMQ同样会阻塞生产者,这样可以避免因非持久化的消息持续换页而耗尽磁盘空间导致服务器崩溃。

默认情况下:磁盘预警为50MB的时候会进行预警。表示当前磁盘空间第50MB的时候会阻塞生产者并且停止内存消息换页到磁盘的过程。
这个阈值可以减小,但是不能完全的消除因磁盘耗尽而导致崩溃的可能性。比如在两次磁盘空间的检查空隙内,第一次检查是:60MB ,第二检查可能就是1MB,就会出现警告。

通过命令方式修改如下:

rabbitmqctl set_disk_free_limit  <disk_limit>
rabbitmqctl set_disk_free_limit memory_limit  <fraction>
disk_limit:固定单位 KB MB GB
fraction :是相对阈值,建议范围在:1.0~2.0之间。(相对于内存)

通过配置文件配置如下:

disk_free_limit.relative = 3.0
disk_free_limit.absolute = 50mb