RabbitMQ 中的内存告警问题

Rabbitmq_memory_alarms

Posted by BlueFat on Wednesday, July 18, 2018

Memory Alarms

在启动了 RabbitMQ 后,若执行过 rabbitmqctl set_vm_memory_high_watermark fraction 命令,RabbitMQ server 会探测计算机上已安装 RAM 总量;默认情况下,当 RabbitMQ server 使用了超过 40% 的 RAM 内存时,会触发内存告警并阻塞住所有 connection ;一旦告警被解除(例如当 server 将消息 page out 到磁盘时,或者将消息 delivery 到客户端时)常规服务能力就能够恢复了;

内存阈值默认被设置为安装 RAM 的 40%

⚠️ 该值并不会真正阻止 RabbitMQ server 使用超过 40% 的内存,而只是一个会令 publisher 开始被阻塞的点;在最坏的情况下,由于 Erlang 垃圾回收器的原因,可能会导致内存使用量被 double(默认情况下为 RAM 的 80%);因此强烈建议开启操作系统本身的 swap 或 page 功能;

在 32-bit 体系架构中,每个进程可用内存的限制为 2GB ;而常规实现的 64-bit 体系架构(即AMD64 和 Intel EM64T)中仅允许每个进程使用区区 256TB ;64-bit Windows 更进一步将其限制为8TB ;另外需要注意的是,就算在 64-bit 操作系统中,一个 32-bit 进程通常也只会使用最大 2GB 的地址空间;

Configuring the Memory Threshold

可以通过配置文件调整触发流控机制的内存阈值;下面的示例中将阈值设置成默认的 0.4 :

[{rabbit, [{vm_memory_high_watermark, 0.4}]}].

默认值 0.4 代表了 40% 的已安装 RAM 或者 40% 的可用虚拟地址空间(比前者更小);例如在一个32-bit 平台上,如果你安装了 4GB 的 RAM ,那么 40% 的 4GB 为 1.6GB ,但是在 32-bit 的 Windows 上,通常会限制进程只能使用 2GB 内存,因此这里实际得到的阈值为 2GB 的 40% ,即 820MB ;

另一种方案为,直接设置节点可用内存阈值为一个具体数值;下面的例子中设置阈值为 1073741824 字节(1024 MB) :

[{rabbit, [{vm_memory_high_watermark, {absolute, 1073741824}}]}].

与上面相同的例子,但使用了内存单位 MiB:

[{rabbit, [{vm_memory_high_watermark, {absolute, "1024MiB"}}]}].

如果上面设置的绝对数值超过了实际安装的 RAM 大小,或者可用的虚拟地址空间大小,阈值会被自动调整为两者中较小的那个值;

在 RabbitMQ server 启动时,内存使用限制信息会输出到 RABBITMQ_NODENAME.log 文件中:

=INFO REPORT==== 29-Oct-2009::15:43:27 ===
Memory limit set to 2048MB.

可以通过 rabbitmqctl status 命令查询内存阈值的具体数值;

可以在 broker 处于运行状态时进行阈值的修改,只需执行 rabbitmqctl set_vm_memory_high_watermark fraction 或者 rabbitmqctl set_vm_memory_high_watermark absolute memory_limit 命令;

可以在上述命令中直接使用内存单位(如 MiB);

通过上述命令进行变更后,修改在 broker 停止运行前一直有效;若想 broker 重启后仍然有效,需要将相应的配置写入到配置文件中;

在具有 hot-swappable RAM 的系统中,内存限制会有所不同,when this command is executed without altering the threshold, due to the fact that the total amount of system RAM is queried.

Disabling all publishing

若设置 set_vm_memory_high_watermark 为 0 则会立刻触发内存告警 ,并且令所有的 publishing 行为立即停止(这对于希望实现全局范围内进行 publish 停止功能来说非常有用);

设置命令为

rabbitmqctl set_vm_memory_high_watermark 0

Limited Address Space

当在 64 bit 的操作系统(或者 32 bit 带有 PAE 的操作系统)上将 RabbitMQ 运行在 32 bit 的 Erlang VM 中时,可访问的内存是受限的;服务器会检测到这种情况,并记录如下日志信息:

=WARNING REPORT==== 19-Dec-2013::11:27:13 ===
Only 2048MB of 12037MB memory usable due to limited address space.
Crashes due to memory exhaustion are possible - see
http://www.rabbitmq.com/memory.html#address-space

内存告警系统并不是完美的;尽管停止 publishing 行为通常会阻止任何后续内存使用,但仍有可能存在其他东东继续内存消耗;当发生这种情况时,通常物理内存会被耗尽,之后操作系统会开始进行 swap 操作;但是当运行在受限地址空间的情况下,内存使用超限将会导致 VM 崩溃;

因此,强烈建议在 64 bit 操作系统上只使用 64 bit Erlang VM ;

Configuring the Paging Threshold

在 broker 真正达到内存使用上限并阻塞 publishing 行为前,会尝试通过 page out 方式将 queue 中内容换出到磁盘,以释放内存占用;page out 行为是同时针对 persistent 和 transient 消息的(persistent 消息已经存在于磁盘上了,page out 操作只是将其他信息从内存中清除干净);

默认情况下,page out 行为开始于 broker 的内存占用达到了阈值 50% 的时候;也就是说,当默认的高水位(阈值)设置为 0.4 时,内存使用量在达到 20% 后就会触发 page out 操作;可以通过 vm_memory_high_watermark_paging_ratio 配置项进行调整,默认值为 0.5 :

[{rabbit, [{vm_memory_high_watermark_paging_ratio, 0.75},
         {vm_memory_high_watermark, 0.4}]}].

上述配置会在内存使用达到 30% 时开始进行 page out 操作,达到 40% 时阻塞 publishing 行为 ;

⚠️ 设置 vm_memory_high_watermark_paging_ratio 的值大于 1.0 是可以的;在这种情况下,queues 将不会将其内容 page 到磁盘上;在这种情况下,如果 memory alarm 被触发了,producer 会照上面所说的被阻塞;

Unrecognised platforms

如果 RabbitMQ server 无法识别你的系统,其会在 RABBITMQ_NODENAME.log 文件中附加如下告警信息,其中假定系统安装了 1GB 的 RAM :

=WARNING REPORT==== 29-Oct-2009::17:23:44 ===
Unknown total memory size for your OS {unix,magic_homebrew_os}. Assuming memory size is 1024MB.

在这种情况下,vm_memory_high_watermark 配置值会被用作放大假定的 1GB RAM 的乘数;若 vm_memory_high_watermark 被设置为 0.4 ,RabbitMQ 的内存阈值将被设置为 410MB ,即无论何时 RabbitMQ 使用了超过 410MB 的内存,都会导致 producer 被阻塞;也就是说,当 RabbitMQ 无法识别你的平台时,如果你实际安装了 8GB RAM ,并且你想让 RabbitMQ 在内存使用超过 3GB 时阻塞 producer ,你就可以设置 vm_memory_high_watermark 为 3 ;

关于推荐 RAM 水位设置,可以参考 《RabbitMQ 之生产环境配置检查表》;


官网原文:这里

链接

RabbitMQ 中的内存告警问题