5、RabbitMQ持久化和内存磁盘管理
1、RabbitMQ的持久化机制
1.1、持久化的三个层级
1.1.1、交换机持久化
- 作用:保存交换机的元数据(包括交换机名称、类型、绑定关系等配置),服务重启后可以恢复交换机结构。
- 配置:创建交换机时通过
durable参数控制:durable=true为持久化,durable=false为非持久化。 - 说明:非持久化交换机重启后会被直接删除,后续生产者发消息会因找不到交换机导致消息丢失;仅存储配置,不存储消息本身。

1.1.2、队列持久化
- 作用:保存队列的元数据(队列名称、属性配置等),服务重启后可以恢复队列结构。
- 配置:创建队列时同样通过
durable参数控制。 - 说明:如果队列是非持久化,重启后队列会被删除,队列内所有消息都会丢失(无论消息是否设置持久化);仅存储队列结构,不保证消息本身不丢失。

1.1.3、消息持久化
- 作用:将消息本身的内容写入磁盘,服务重启后消息可以保留。
- 配置:发送消息时通过
deliveryMode参数设置:1代表非持久化(存在内存),2代表持久化(写入磁盘)。
不管是持久化的消息还是非持久化的消息,都是可以写入到磁盘的
- 持久化消息

- 非持久化消息

1.2. 保证消息不丢的完整条件
三个层级的持久化需要全部开启才能保证RabbitMQ重启后消息不丢失,任意一个环节不开启都可能丢数据:
- 仅开消息持久:队列非持久→重启队列删除,消息全丢;
- 仅开队列持久:消息非持久→消息存在内存,重启消息丢;
- 仅开交换机+队列:消息不持久→消息依旧丢。
1.3、持久化的注意事项
1.3.1、性能取舍
持久化需要频繁磁盘IO,性能远低于内存存储,全开持久化的吞吐量通常比非持久化低一个数量级左右。如果业务允许少量消息丢失(比如日志上报、统计类业务),可以不开启持久化换取更高性能。
1.3.2、无法做到100%不丢消息
RabbitMQ写入持久化消息时,默认是先写到操作系统的页缓存,不会立刻刷入物理磁盘,如果刷盘前发生宕机,依旧可能丢消息。生产环境一般会配合生产者发布确认机制(Publisher Confirms),只有消息成功写入磁盘后才给生产者回确认,进一步降低丢消息概率。
1.3.3、集群层面的持久化
RabbitMQ集群的元数据(交换机、队列配置)默认存储在磁盘节点,如果集群全部都是内存节点,重启后所有元数据会全部丢失,因此生产环境集群至少保留一个磁盘节点保证元数据持久化。
1.3.4、惰性队列优化
RabbitMQ 3.6之后引入了惰性队列(Lazy Queue),默认队列会把消息尽量存在内存,消息堆积时才换页到磁盘(参见2.2);惰性队列会直接把消息存在磁盘,支持百万级消息堆积,默认就是持久化的,适合大消息堆积的业务场景。
2、RabbitMQ内存控制
当内存使用超过配置的阈值或者磁盘剩余空间低于配置的阈值的时候,Rabbit MQ会阻塞客户端连接,并停止接收从客户端发送来的消息,以此避免RabbitMQ服务崩溃,客户端与服务器端的心跳检测也会失效。
2.1、内存阈值配置
内存的 阈值可以通过下面命令临时调整内存阈值大小(默认值0.4,即40%,也可以用绝对值)
rabbitmqctl set_vm_memory_hight_watermark <fraction>
# 如:
rabbitmqctl set_vm_memory_hight_watermark absolute 50mb
注意:
- 单独在某个节点上调整参数,集群默认不会自动将其同步到其它节点上,自动同步的信息只包含vhost、交换机、队列等
- 通过命令修改的阈值在broker重启后会失效,如果要始终保持生效状态,可以通过修改配置文件然后重启broker的方式,修改
/etc/rabbitmq/rabbitmq.conf文件,修改参数vm_memory_high_watermark.ralative或者vm_memory_high_watermark.absolute
2.2、RabbitMQ的内存换页
在某个broker节点触及内存并阻塞生产者之前(默认情况下,在内存达到配置的阈值的50%的时候会进行换页,可以通过vm_memory_high_watermark_paging_ratio这个参数进行修改,如果这个值配置成大于1的数,表示禁止换页功能),它会尝试将内存队列中的消息换页到磁盘以释放内存空间。
前面的图中可以看到持久化和非持久化的消息都会被转储到磁盘中,其中持久化的消息本身就在磁盘中有一份副本,这里会将持久化的消息从内存里清除掉
3、RabbitMQ的磁盘告警
在rabbitmq中,当磁盘剩余空间低于一个阈值时,rabbitmq同样也会阻塞生产者,这样可以避免因非持久化的消息持续换页而耗尽磁盘空间导致服务崩溃。在默认的情况下, 这个阈值是50mb,即当剩余磁盘空间低于50mb的时候会阻塞生产者并停止内存中的消息进行换页。
这个阈值可以适当调小,但是不能完全消除因为磁盘耗尽导致的崩溃可能性,因为空间检测也是需要时间的,如果是在两次磁盘空间检测的间隙磁盘空间从大于50mb变为0mb,服务依然也会崩溃。
3.1、磁盘阈值配置
磁盘告警的阈值可以通过命令来调整:
rabbitmqctl set_disk_free_limit <disk_limit>
rabbitmqctl set_disk_free_limit mem_ralative <fraction>
disk_limit:固定大小,单位是KB、MB、GB
fraction:为相对值,建议取值在1.0~2.0之间
对应的配置参数
disk_free_limit.relative和disk_free_limit.absolute

