⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 blog.csdn.net/yi_qingjun/article/details/128448658 「百慕卿君」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

前面介绍了 RabbitMQ 消息收发与交换机、消息确认机制、重试机制、队列与消息过期等相关的知识点,今天我将详细的为大家介绍 RabbitMQ 持久化、存储机制与内存管理相关知识,希望大家能够从中收获多多!如有帮助,请点在看、转发支持一波!!!

持久化

持久化对象

rabbitmq的持久化分为三个部分:

  • 交换器的持久化。
  • 队列的持久化。
  • 消息的持久化。
交换器持久化
  • 交换器的持久化是通过在声明交换器时, 指定Durability参数为durable实现的。
  • 若交换器不设置持久化,在rabbitmq服务重启之后,相关的交换器元数据会丢失,但消息不会丢失,只是不能将消息发送到这个交换器中。
  • 所以在声明交换器时,都要设置持久化。
  • 在web监控创建时,默认也是持久化模式,指定持久化模式带有标识“D”。

队列持久化
  • 交换器的持久化是通过在声明交换器时, 指定Durability参数为durable实现的。
  • 若队列不设置持久化,在rabbitmq服务重启之后,相关队列的元数据和消息数据同时丢失。
  • 若队列设置持久化,只能保证队列本身的元数据不会因异常情况而丢失,但是并不能保证内部所存储的消息不会丢失。要确保消息不会丢失,需要将其设置为持久化。
  • 在web监控创建时,默认也是持久化模式,指定持久化模式带有标识“D”。

消息持久化
  • 消息的持久化可以通过消息的投递模式来实现,属于代码层面上的。
  • 在web监控页面没有指定持久化的属性参数,但是消息一般都是要设置持久化的,所以在web页面我们可以看到发送消息时下面都时嗲有持久化标识的。
  • 但是将所有消息都设置为持久化,会严重影响rabbitmq服务器性能,写入磁盘的速度比写入内存的速度慢得不只一点点。所以对于可靠性不是那么高的消息可以不采用持久化处理以提高整体的吞吐量。在选择是否要将消息持久化时,需要在可靠性和吐吞量之间做一个权衡。

总结要点

将交换器、队列、消息都设置了持久化之后也不能百分之百保证数据的丢失。

  • 从消费者来说,如果在订阅消费队列时将 autoAck 参数设置为 true,那么当消费者接收到相关消息之后,还没来得及处理就宕机了,这样也算数据丢失。这种情况很好解决,将autoAck 参数设置为 false,并进行手动确认。
  • 在持久化的消息正确存入rabbitmq之后,还需要有一段时间(虽然很短,但是不可忽视) 才能存入磁盘之中。如果在这段时间内rabbitmq服务节点发生了宕机、重启等异常情况,消息保存还没来得及落盘,那么这些消息将会丢失。这种情况可以使用镜像队列来解决。

存储机制

前面提到的消息持久化,其实是在rabbitmq的“持久层”中完成的。不管是持久化的消息,还是非持久化的消息都可以被写入到磁盘。

  • 持久化的消息在到达队列时就入盘,而且还可以设置持久化的消息在内存中也保存一份备份,这么做可以提高业务效率,当内存吃紧时会从内存中清除。
  • 非持久化的消息一般只保存在内存中,在内存吃紧的时候会被换入到磁盘中,以节省内存空间。

存储方式

持久层是一个逻辑上的概念,实际包含两个部分:

  • 队列索引 (rabbit_queue_index):负责维护队列中落盘消息的信息,包括消息的存储地点、消息在队列中的位置、是否已被交付给消费者、是否已被消费者 ack 等。每个队列都有与之对应的一个队列索引。

  • 消息存储(rabbit_msg_store):而消息存储是以键值对的形式存储消息,它被所有队列共享,所以在每个节点中有且只有一个。从技术层面上来说,rabbit_msg_store 具体还可以分两类:

    • msg_store_persistent :负责持久化消息的持久化,重启后消息不会丢失。
    • msg_store_transient:负责非持久化消息的持久化,重启后消息会丢失。
    • 我们一般说消息存储,是习惯性地将 msg_store_persistent 和 msg_store_transient 看成 rabbit_msg_store 一个整体。

存在队列索引里的好处?

  • 性能上的优化。相比存在消息存储里,直接存在队列索引仅需进行一次写操作。而存储在消息存储中的消息则需要两次写操,先写一次索引,再写一次消息存储,因此会有一定的性能提升。注意事项:
  • 若消息直接存在队列索引中,则当消息通过exchange同时路由到多个队列时,此消息会被写到每个队列的索引文件中。
  • 若消息是存在消息存储中,就仅仅只有一个副本。

存储文件

  • 上面提到的消息,是包括消息体、属性和 headers,可以直接存储在队列索引中,也可以保存在消息存储中。

  • rabbitmq启动后,会针对每个vhost会启动两个进程:msg_store_persistent和msg_store_transient,这两个进程作为服务端负责将消息写入文件,从文件读取消息。

    • msg_store_persistent负责将持久化消息写入文件与从文件中读取消息。
    • msg_store_transient负责非持久化消息写入文件与从文件中读取消息。
  • 默认存储文件位置:$rabbitmq home/var/lb/mnesia/rabbit@hostname/路径下,包含queues、msg_store_persistent、msg_store_transient 这3个文件夹。如下图,我这里是指定了存储文件地址。

队列索引.idx文件
  • rabbit_queue_index 中以顺序(文件名从 0 开始累加) 的段文件来进行存储,后缀为“ .idx “。
  • 每个段文件中包含定的 SEGMENT_ENTRY_COUNT 条记录,SEGMENT_ENTRY_COUNT 默认值为16384字节。
  • 每个rabbit_queue_index 从磁盘中读取消息的时候至少要在内存中维护一个段文件,所以设置queue_index_embed_msgs_below参数指定阈值大小时要格外谨慎,一点点增大也可能会引起内存爆炸式的增长。
消息存储.rdq文件
  • 经过 rabbit_msg_store 处理的所有消息都会以追加的方式写入到文件中,当一个文件的大小超过指定的限制 (file_size_lmit)后,关闭这个文件再创建一个新的文件以供新的消息写入,文件后缀是“ .rdq ”。
  • 文件名从0开始进行累加,所以文件名最小的文件也是最老的文件。
  • 在进行消息的存储时,rabbitmq会在ETS (Erlang Term Storage) 表中记录消息在文件中的位置映射 (Index) 和文件的相关信息 (FileSummary)。

读取文件信息:

  • 在读取消息的时候,先根据消息的 ID (msg_id)找到对应存储的文件。

    • 若文件存在并且未被锁住,则直接打开文件,从指定位置读取消息的内容。
    • 若文件不存在,或被锁住,则发送请求由 rabbit_msg_store 进行处理。

删除文件信息:

  • 消息的删除只是从 ETS 表删除指定消息的相关信息,同时更新消息对应的存储文件的相关信息。

  • 执行消息删除操作时,不会立即对在文件中的消息进行删除,先是标记为垃圾数据。

    • 若一个文件中都是垃圾数据时,则删除文件。
    • 若一个文件中存在有效数据,则触发垃圾回收机制,进行文件合并选择性删除。

垃圾回收文件合并机制:

  • 当检测到前后两个文件中的有效数据可以合并在一个文件中,并且所有的垃圾数据的大小和所有文件(至少有3 个文件存在的情况下)的数据大小的比值超过设置的值 GARBAGE_ERACTION (默认值为 0.5) 时,才会触发垃圾回收将两个文件合并。
垃圾回收机制(文件合并)
  • 文件合并前提:

    • 执行合并的两个文件一定是逻辑上相邻的两个文件。
  • 文件合并流程:

    • 第一步,执行合并时首先锁定这两个文件。
    • 第二步,先对前面文件中的有效数据进行整理。
    • 第三步,再将后面文件的有效数据写入到前面的文件。
    • 第四步,更新消息在 ETS 表中的记录。
    • 第五步,最后删除后面的文件。

存储原理

  • 老版本中,都是把较小的消息存储在rabbit_queue_index中,较大的消息存储在rabbit_msg_store中。通过queue_index_embed_msgs_below参数指定消息大小,默认值为4096字节。即消息体、属性以及headers长度累加起来整体小于4096字节的消息将直接存储在队列索引中。
  • 而从3.5.0版本开始,较小的消息是直接存储在队列索引中。
  • 在进行消息的存储时,rabbitmq会在ETS表中记录消息在文件中的映射,以及文件的相关信息。
  • 消息读取时,根据消息ID找到该消息所存储的文件,在文件中的偏移量,然后打开文件进行读取。
  • 消息的删除只是从ETC表删除指定消息的相关信息,同时更新消息对应存储的文件的相关信息(更新文件有效数据大小)。
生产者消息写入原理
  • 每个队列则看成是一个客户端,当生产者发送的消息达到队列时,向服务端请求写,写入过程如下:

    • msg_store_persistent进程将持久化消息写入到服务器的msg_store_persistent目录下,文件名称依次为0.rdq、1.rdq、2.rdq等等。
  • msg_store_transient进程将非持久化消息写入到服务器的msg_store_transient目录下,文件名称依次为0.rdq、1.rdq、2.rdq等等。

  • 第一步,rabbitmq启动后,针对每个vhost开启两个进程,msg_store_persistent进程和msg_store_transient进程。两进程作为服务端,每个队列作为客户端。

  • 第二步,当生产者发送消息到队列时,每个队列都会向两进程发起写入请求。

  • 第三步,两进程开始往磁盘里写入消息。

消费者消息读取原理
  • 第一步,消费者向队列获取消息体。

  • 第二步,队列汇聚消息ID去找落盘文件。

    • 若文件存在,且未被锁住,则直接读取文件内容,返回消息给消费者。
    • 若文件不存在,或已被锁住,则让rabbit_msg_store进程处理。
  • 第三步,队列向两进程发起请求,进程先是通过GC进程去查看文件是否被锁住,同时也会清理垃圾,进行有效数据合并。

    • 若被锁住则解锁,获取消息,返回给消费者。
    • 若清理垃圾后,发现还是没有此消息,则向rabbitmq其他节点发送询问请求。
  • 第四步,其他节点会根据消息ID挨个寻找,直至将rabbitmq集群每个节点找遍,之后返回结果给消费者。

ETS

前文提到ETS,ETS是啥咱们来了解一下,这是偏开发向的,运维可以了解一下。

  • rabbitmq在其内部维护了多张表,每张表作用不同,对应记录的内容也都不同。
  • 有的是记录消息与存储文件的相关信息:消息存储在哪个文件中、在文件中的偏移位置、消息的长度、引用次数、总共有多少个文件、文件中有多少有效消息、左右关联的文件信息等。
  • 有的则是用于操作记录、消息缓存等,以便于减少对文件的实际读写操作。
ETS表

1.第一张表:flying_ets表。

  • 表的作用:

    • 记录消息write、remove的引用计数。
  • 表结构参数释义:

    • CRef参数:表示客户端对应的reference,每个客户端唯一。

    • MsgId参数:表示消息的唯一ID。

    • Count参数:表示消息的引用计数。

2.第二张表:cur_file_cache_ets表。

  • 表的作用:

    • 记录当前正在写的文件的消息缓存计数。
  • 表结构参数释义:

    • MsgId参数:表示消息的唯一ID。
    • Msg参数:表示消息内容。
    • Count参数:表示消息的引用计数。

3.第三张表:msg_store_ets_index表。

  • 表的作用:

    • 记录消息在文件中的索引信息。
  • 表结构参数释义:

    • MsgId参数:表示消息的唯一ID。
    • RefCount参数:表示消息的计数。
    • File参数:表示消息所在的存储文件名称。
    • Offset参数:表示消息在文件中的偏移位置。
    • TotalSize参数:表示消息的长度。

4.第四张表:file_summary_ets表。

  • 表的作用:

    • 记录文件的描述信息。
  • 表结构参数释义:

    • File参数:表示存储文件名称。

    • ValidTotalSize参数:表示存储文件的有效数据大小。

    • Left参数:表示位于该文件左边的文件是哪个。

    • Right参数:表示位于该文件右边的文件是哪个。

    • FileSize参数:表示文件总体大小。

    • Locked参数:表示文件锁定标记,文件合并或删除前会进行锁定。

    • Readers参数:表示当前正在读该文件的客户端个数。

消息的写流程(ETS层面分析)

消息的删除流程(ETS层面分析)

消息的读流程(ETS层面分析)

队列结构

队列的组成:

  • 队列由 rabbit_amgqueue_process 和 backing_queue两部分组成。
  • rabbit_amqqueue_process负责协议相关的消息处理,即接收生产者发布的消息、向消费者交付消息、处理消息的确认 (包括生产端的 confirm 和消费端的 ack) 等。
  • backing_queue是消息存储的具体形式和引擎,并向rabbit_amqqueue_process提供相关的接口以供调用。

消息投递:

  • 若消息投递的目的队列是空的,并且有消费者订阅了此队列,则该消息直接发给消费者,不经过队列。
  • 若消息无法直接投递给消费者时,需要暂时将消息存入队列,以便重新投递。消息存入队列后,会随着系统的负载在队列中不断地流动,消息的状态会不断发生变化。
消息状态分类

消息的4 种状态:

  • alpha状态:表示消息内容 (包括消息体、属性和 headers) 和消息索引都存储在内存中。
  • beta状态:表示消息内容保存在磁盘中,消息索引保存在内存中。
  • gamma状态:表示消息内容保存在磁盘中,消息索引在磁盘和内存中都有。
  • delta状态:表示消息内容和索引都在磁盘中。

注意事项:

  • 对于持久化的消息,消息内容和消息索引都必须先保存在磁盘上,才会处于上述状态中的种。
  • gamma 状态的消息是只有持久化的消息才会有的状态。
消息状态对资源影响
  • rabbitmq在运行时,会根据统计的消息传送速度,定期计算一个当前内存中能够保存的最大消息数量(target_ram_count)。

    • 若alpha 状态的消息数量大于此值时,就会引起消息的状态转换,多余的消息可能会转换到beta 状态、gamma 状态或者 delta 状态。
    • 区分这 4 种状态的主要作用是满足不同的内存和CPU需求。

消息状态对服务器资源的影响:

  • alpha状态最耗内存,但很少消耗 CPU。
  • delta状态基本不消耗内存,但是需要消耗更多的 CPU 和磁盘 I/O 操作。

注意事项:

  • delta 状态需要执行两次I/O 操作才能读取到消息。一次是读消息索引 (从 rabbit_queue_index 中),一次是读消息内容(从 rabbit_msg_store 中)。
  • beta 和 gamma 状态都只需要一次I/0 操作就可以读取到消息 (从 rabbit_msg_store中)。
队列中的消息状态分布结构
  • 对于普通的没有设置优先级和镜像的队列来说,backing_queue的默认实现是rabbit_variable_queue。其内部通过 5 个子队列 Q1、Q2、Delta、Q3 和 Q4 来体现消息的各个状态。
  • 整个队列包括rabbit_amgqueue_process和backing_queue 的各个子队列。

队列中的消息状态结构分布:

  • Q1、Q4 只包含 alpha 状态的消息。也就是消息体和消息索引都在内存中的消息。
  • Q2 、Q3 包含 beta 和gamma 状态的消息,
  • Delta 只包含 delta 状态的消息。也就是消息内容和索引都在磁盘中的消息。

队列中的消息流动状态变化:

  • 一般情况下,消息按照 Q1——> Q2——> Delta——> Q3——> Q4 顺序进行流动,但并不是每一条消息都一定会经历所有的状态,这个取决于当前系统的负载状况。

  • 从Q1至Q4的过程,就相当于消息内存——> 磁盘——> 内存的过程。

    • 当队列负载高,占用极大的内存时,可以把一部分消息放入磁盘,以此节省内存空间。
    • 当队列负载降低,内存资源释放出来时,这部分消息又渐渐回到内存被消费者获取,使得整个队列具有很好的弹性。

消费者对队列中消息状态的影响变化

消费消息对队列中的消息状态变化流程:

  • 第一步:当消费者获取消息时,首先会从 Q4 中获取内存中消息,如果获取成功则返回。

    • 若Q4为空,则尝试从 Q3 中获取消息,进入第二步。
  • 第二步:从Q3中获取消息时,系统首先会判断Q3是否为空,如果为空则返回队列为空,即此时队列中无消息。

    • 若Q3不为空,则取出 Q3 中的消息并和Delta中的消息长度做已判断。如果Q3和Delta都为空,则可以认为 Q2、Delta、03、Q4 全部为空,此时将Q1中的消息直接转移至 Q4,下次直接从Q4 中获取消息。
    • 若Q3为空,Delta 不为空,则将 Delta 的消息转移至Q3中,下次可以直接从Q3中获取消息。
  • 第三步:在将消息从 Delta 转移到 Q3 的过程中,是按照索引分段读取的,首先读取某一段,然后判断读取的消息的个数与Delta 中消息的个数是否相等,如果相等,则可以判定此时 Delta 中已无消息,则直接将Q2 和刚读取到的消息一并放入到 Q3 中;如果不相等,仅将此次读取到的消息转移到 Q3。

结论:

  • 通常在负载正常时,如果消息被消费的速度不小于接收新消息的速度,对于不需要保证可靠不丢失的消息来说,极有可能只会处于 alpha 状态。
  • 对于 durable 属性设置为 true 的消息一定会进入 gamma 状态,并且在开启 publisher confirm机制时,只有到了 gamma 状态时才会确认该消息已被接收。
  • 若消息消费速度足够快、内存也充足,这些消息也不会继续走到下一个状态。

影响及应对措施:

  • 在系统负载较高时,已接收到的消息若不能很快被消费掉,这些消息就会进入到很深的队列中去,这样会增加处理每个消息的平均开销。因为要花更多的时间和资源处理“堆积”的消息,如此用来处理新流入的消息的能力就会降低,使得后流入的消息又被积压到很深的队列中继续增大处理每个消息的平均开销,继而情况变得越来越恶化,使得系统的处理能力大大降低。

  • 应对这一问题一般有 3 种措施:

    • 1.增加 prefetch_count值,即一次发送多条消息给消费者,加快消息被消费的速度。这个值跟消息分发有关,开发人员代码中使用设置。
    • 2.采用 multiple ack,降低处理 ack 带来的开销。可以回顾消费端的确认机制,也是开发人员设置。
    • 3.流量控制。

内存磁盘告警

对运维来说,中间件对服务器资源状态的影响需要严格控制,所以本小结就非常重要了。

  • 当内存使用超过配置的阈值或者磁盘剩余空间低于配置的阈值时,rabbitmq都会暂时阻塞(block) 客户端的连接(Connection)并停止接收从客户端发来的消息,以此避免服务崩溃。同时,客户端与服务端的心跳检测也会失效。可以通过命令或者 Web 管理界面来查看它的状态。

Connection阻塞状态有两种:

  • blocking状态:对应于并不试图发送消息的 Connection,比如消费者关联的 Connection,这种状态下的 Connection 可以继续运行。
  • blocked状态:对应于一直有消息发送的 Connection,这种状态下的 Connection 会被停止发送消息。

注意事项:

  • 注意在一个集群中,如果一个 Broker 节点的内存或者磁盘受限,都会引起整个集群中所有的Connection 被阻塞。
[root@node1 rabbitmq]# rabbitmqctl  list_connections

内存告警

内存告警:

  • 所谓内存告警,就是当rabbitmq使用的内存资源超过了在配置文件中设置的阈值,就会触发告警,此时会阻塞所有生产者的连接。
  • 当告警被解除,比如积压的消息被消费、消息从内存写入磁盘磁盘释放内存资源等情况,一切都会恢复正常。

内存阈值:

  • 默认情况下vm_memory_high_watermark.relative的值为0.4,即内存阈值为 0.4,表示当rabbitmq使用的内存超过 40%时,就会产生内存告警并阻塞所有生产者的连接。
  • rabbitmq默认使用内存阈值为40%,只是代表当超过这个值时,会限制生产者的连接,不代表此时的rabbitmq不能使用超过 40%的内存。
  • 在最坏的情况下,Erlang的垃圾回收机制会导致两倍的内存消耗,也就是 80%的使用占比。
内存阈值设置
  • 在3.11.4版本中,启动rabbitmq服务时,打印得日志可以看出,默认使用的内存阈值时0.4。
  • 官方建议设置此值区间为:0.4~0.66 ,不建议取值超过 0.7。

配置文件百分比设置

配置文件中设置需要重启rabbitmq服务才能生效,相比下文中的命令设置,服务器重启也同样生效。所以生产环境中建议是在配置文件中修改。

1.此时内存阈值为默认0.4,日志显示。

2.修改配置文件内存阈值参数vm_memory_high_watermark.relative,重启服务,此时日志显示就是0.6的配置了。

3.在监控页面也可以看到阈值

绝对值设置

上面是通过占用服务器总内存的百分比设置,也可以直接用指定配置参数vm_memory_high_watermark.absolute用绝对值设置,默认单位为 B,也可以指定单位设置。

内存阈值绝对值怎么算?

  • 假设服务器内存为4GB,则rabbitmq服务的内存值的绝对值为4GBx0.4=1.6GB。如果是 32 位的 Windows 操作系统,那么可用内存被限制为 2GB,也就意味着 RabbitMQ 服务的内存闽值的绝对值为 820MB 左右。

1.修改配置文件参数,取消注释,重启服务,查看日志。

2.监控页面也是即时更改过来。

  • 也可以不使用字节来设置,换算太麻烦,直接指定GB、MB等单位会更方便。

1.修改配置文件参数vm_memory_high_watermark.absolute,指定设置内存阈值绝对值为1GB,重启服务。

2.重启服务,查看日志显示为1G。

命令设置

绝对值设置:rabbitmqctl set_vm_memory_high_watermark absolute {memory limit}

  • { memory limit}参数,代表设置的内存阈值绝对值大小,可以指定计量单位,GB、KB等,默认使用的是字节单位。

百分制设置:rabbitmqctl set_vm_memory_high_watermark {fraction]

  • {fraction]参数,代表设置的内存阈值百分比大小。

1.使用绝对值命令设置内存阈值大小为2GB。

#指定单位。
[root@node1 rabbitmq]# rabbitmqctl set_vm_memory_high_watermark absolute 2GB
Setting memory threshold on rabbit@node1 to 2GB bytes ...

2.查看日志,显示为2GB。

3.不指定计量单位设置时,使用的是字节计量单位。如下设置为1GB,不指定计量单位。

#不指定单位设置。
[root@node1 rabbitmq]# rabbitmqctl set_vm_memory_high_watermark absolute 1073741824

4.使用百分制命令设置内存阈值为0.6。

#使用百分制设置。
[root@node1 rabbitmq]# rabbitmqctl set_vm_memory_high_watermark 0.6

内存换页设置

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

设置参数:vm_memory_high_watermark_paging_ratio。

  • 当设置为大于 1 的浮点数,这种配置相当于禁用了换页功能。

  • 默认情况下,在内存到达内存闯值的 50%时会进行换页动作。也就是说,在默认的内存阙值为 0.4 的情况下,当内存超过 0.4X0.5=0.2 时会进行换页动作。

Erlang虚拟机内存消耗计算策略

设置参数:vm_memory_calculation_strategy。

  • ’ 默认为rss策略,可选策略有:allocated 、 rss 、 legacy 。

执行内存检查的时间间隔

设置参数:memory_monitor_interval,单位毫秒。

磁盘告警

磁盘告警

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

配置参数:disk_free_limit.absolute

  • 默认情况下,磁盘阈值为 50MB,表示当磁盘剩余空间低于50MB时,会阻塞生产者并停止内存中消息的换页动作。
注意事项
  • 这个阙值的设置可以减小,但不能完全消除因磁盘耗尽而导致崩溃的可能性,比如在两次磁盘空间检测期间内,磁盘空间从大于 50MB 被耗尽到 OMB。
  • 一个相对谨慎的做法是将磁盘阙值设置为与操作系统所显示的内存大小一致。
定期检查磁盘剩余空间频率
  • rabbitmq会定期检测磁盘剩余空间,检测频率与上一次执行检测到的磁盘剩余空间大小有关。
  • 正常情况下,每 10 秒执行一次检测,随着磁盘剩余空间与磁盘闽值的接近,检测频率会有所增加。
  • 当要到达磁盘闽值时,检测频率为每秒 10 次,这样有可能会增加系统的负载。
磁盘阈值设置
配置文件绝对值设置

默认设置的是50MB,单位字节。服务启动时也会显示此设置。

也可以指定单位设置,GB、mb、KB。

相对值设置

还可以根据服务器内存的大小和磁盘阈值设置一个相对的比值。

设置参数:disk_free_limit.relative

正常情况下,建议 disk free limit.mem relative 的取值为 1.0 和2.0之间。

命令设置

命令设置,在服务器重启后失效,不要用,只做知识了解。

绝对值设置:rabbitmqctl set_disk_free_limit {disk_limit}

相对值设置:rabbitmqctl set_disk_free_limit mem_relative {fraction}

  • {fraction}参数代表,服务器内存大小和磁盘阈值的比值。

1.设置为2GB,查看日志。不指定单位默认使用字节单位。

[root@node1 rabbitmq]# rabbitmqctl set_disk_free_limit 2GB
Setting disk free limit on rabbit@node1 to 2GB bytes ...

2.默认使用字节单位。

3.相对值设置。

#将磁盘阈值设置于服务器内存一样大。
[root@node1 rabbitmq]# rabbitmqctl set_disk_free_limit mem_relative 1.0
Setting disk free limit on rabbit@node1 to 1.0 times the total RAM ...

以上就是关于RabbitMQ 持久化、存储机制、ETS、队列结构、消息状态、内存告警、磁盘告警等知识详解内容。

文章目录
  1. 1. 持久化
    1. 1.0.1. 持久化对象
      1. 1.0.1.0.1. 交换器持久化
      2. 1.0.1.0.2. 队列持久化
      3. 1.0.1.0.3. 消息持久化
  2. 1.0.2. 总结要点
  • 2. 存储机制
    1. 2.0.1. 存储方式
    2. 2.0.2. 存储文件
      1. 2.0.2.0.1. 队列索引.idx文件
      2. 2.0.2.0.2. 消息存储.rdq文件
      3. 2.0.2.0.3. 垃圾回收机制(文件合并)
  • 2.0.3. 存储原理
    1. 2.0.3.0.1. 生产者消息写入原理
    2. 2.0.3.0.2. 消费者消息读取原理
  • 2.0.4. ETS
    1. 2.0.4.0.1. ETS表
    2. 2.0.4.0.2. 消息的写流程(ETS层面分析)
    3. 2.0.4.0.3. 消息的删除流程(ETS层面分析)
    4. 2.0.4.0.4. 消息的读流程(ETS层面分析)
  • 2.0.5. 队列结构
    1. 2.0.5.0.1. 消息状态分类
    2. 2.0.5.0.2. 消息状态对资源影响
    3. 2.0.5.0.3. 队列中的消息状态分布结构
    4. 2.0.5.0.4. 消费者对队列中消息状态的影响变化
  • 3. 内存磁盘告警
    1. 3.0.1. 内存告警
      1. 3.0.1.0.1. 内存阈值设置
      2. 3.0.1.0.2. 配置文件百分比设置
    2. 3.0.1.1. 绝对值设置
      1. 3.0.1.1.1. 命令设置
      2. 3.0.1.1.2. 内存换页设置
      3. 3.0.1.1.3. Erlang虚拟机内存消耗计算策略
      4. 3.0.1.1.4. 执行内存检查的时间间隔
  • 3.0.2. 磁盘告警
    1. 3.0.2.0.1. 磁盘告警
    2. 3.0.2.0.2. 注意事项
    3. 3.0.2.0.3. 定期检查磁盘剩余空间频率
    4. 3.0.2.0.4. 磁盘阈值设置
    5. 3.0.2.0.5. 配置文件绝对值设置
    6. 3.0.2.0.6. 相对值设置
    7. 3.0.2.0.7. 命令设置