RabbitMQ Erlang 内存分配器监控:基于 rabbitmq-prometheus 与 Grafana 的 Erlang VM 内存全景分析
RabbitMQ Erlang 内存分配器监控基于 rabbitmq-prometheus 与 Grafana 的 Erlang VM 内存全景分析【免费下载链接】rabbitmq-serverOpen source RabbitMQ: core server and tier 1 (built-in) plugins项目地址: https://gitcode.com/gh_mirrors/ra/rabbitmq-server本文围绕 RabbitMQ 官方 Prometheus 生态中的Erlang-Memory-AllocatorsGrafana 仪表盘展开讲解如何从erts_alloc视角剖析 Erlang VM 的内存构成——从进程常驻内存RSS到 11 种分配器allocator的 Block/Carrier 使用情况并结合 rabbitmq-prometheus 插件的源码与指标定义给出可落地、可检索的监控与排障方案。读完本文你将掌握该仪表盘每一个指标面板背后的数据来源、PromQL 查询逻辑以及如何快速在本地 RabbitMQ Prometheus Grafana 环境中启用并复现这套监控体系。一、为什么需要从分配器视角看 Erlang VM 内存RabbitMQ 运行在 Erlang/OTP 之上其内存管理由 Erlang 虚拟机内部的erts_alloc子系统负责。erts_alloc并不是一个单一的内存池而是由一组职责不同的分配器allocator组成——每个分配器面向特定类型的内存对象如 ETS 表、进程堆、二进制数据等拥有独立的块Block与载体Carrier管理策略。因此单看操作系统层面的 RSS常驻内存无法回答“内存到底花在哪里”的问题是 ETS 膨胀还是二进制堆增长还是进程堆碎片化Grafana 官方发布的Erlang-Memory-Allocators仪表盘本仓库中的发布说明见 erlang-memory-allocators-11350.md仪表盘定义见 Erlang-Memory-Allocators.json正是为回答这个问题而设计它把 Erlang VM 的分配器级内存细分为可筛选、可对比、可回溯时间序列的 Grafana 面板帮助运维人员快速定位内存增长来自哪个分配器、属于哪种分配结构。二、仪表盘核心指标体系该仪表盘以“从erts_alloc视角看 Erlang VM 内存使用率”为核心展示两大类数据1. Resident Set SizeRSS 常驻内存以rabbitmq_process_resident_memory_bytes指标为准反映 RabbitMQ 节点进程在操作系统层面的常驻物理内存。这是内存监控的“最外层”指标也是判断节点是否逼近内存高水位memory high watermark的第一道防线。从源码看该指标由 prometheus_rabbitmq_core_metrics_collector.erl 在node_coarse_metrics组中定义为 Gauge{2, undefined, process_resident_memory_bytes, gauge, Memory used in bytes, mem_used},对应地同组还有resident_memory_limit_bytes内存高水位阈值来自mem_limit与erlang_gc_reclaimed_bytes_totalGC 回收字节数等指标可以在同一张时间序列图中对比“已用”与“上限”判断是否接近内存告警线。完整指标清单可查阅 metrics.md。2. Allocated分配器已分配内存Total总分配量所有分配器向操作系统申请的载体Carrier总大小对应carriers_size。Used已使用量载体内部实际被块Block占用的内存对应blocks_size。Unused未使用量Total - Used即已申请但尚未被占用的“余量”反映内存的预分配与碎片情况。在仪表盘中未使用量由以下 PromQL 求得截取自仪表盘 JSONsum (erlang_vm_allocators{usagecarriers_size} * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster$rabbitmq_cluster, namespace$namespace, rabbitmq_endpoint$endpoint, rabbitmq_node$rabbitmq_node}) - sum (erlang_vm_allocators{usageblocks_size} * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster$rabbitmq_cluster, namespace$namespace, rabbitmq_endpoint$endpoint, rabbitmq_node$rabbitmq_node})该表达式同时演示了 rabbitmq-prometheus 的多集群标签注入机制通过rabbitmq_identity_info将rabbitmq_cluster、rabbitmq_node、namespace、endpoint等身份标签group_left关联到原始指标上从而支持在同一个 Prometheus 实例中区分多个 RabbitMQ 集群/节点。三、11 种分配器类型详解仪表盘按分配器类型展示内存占用并提供Min / Max / Avg / Current四种统计口径既看瞬时值也看峰值与均值。文档列出的分配器共 11 种分配器主要用途binary_alloc二进制binary数据如消息体、大字符串driver_alloc端口驱动port driver分配的二进制与内存eheap_allocErlang 进程堆process heapets_allocETS 表数据exec_alloc模拟器执行相关数据如栈fix_alloc频繁创建的小型固定大小对象如进程控制块 PCBliteral_alloc字面量literal数据ll_alloc链接列表linked list数据sl_alloc短生命周期short-lived数据std_alloc通用standard分配器多数对象的默认去向temp_alloc临时temporary数据说明不同 Erlang/OTP 版本的分配器集合可能略有差异以上用途描述基于erts_alloc的常规分工在 RabbitMQ 集群中binary_alloc、ets_alloc、eheap_alloc与std_alloc通常是内存排查中最先需要关注的分配器。在仪表盘中这些分配器通过 Prometheus 标签alloc区分面板按分配器分别绘制 Carrier/Block 占用曲线见 JSON 中的sum by(alloc) (erlang_vm_allocators{usagecarriers_size} ...)查询并通过$memory_allocator模板变量支持多选与“All”。四、三种分配结构Multiblock / Multiblock Pool / Singleblock对于每一个分配器仪表盘进一步按内存的组织结构拆分这在erts_alloc中对应三种分配机制Multiblock多块标签kindmbcs从大块载体Carrier中切分出多个大小不一的块Block。块尺寸可以不同适合大小不一的对象这是多数分配器的主要工作方式。Multiblock Pool多块池标签kindmbcs_pool多块载体的池化变体通过多块池MBC pool减少同步开销、提升多调度器并发下的分配性能。Singleblock单块标签kindsbcs一块载体只承载一个块适合超大内存对象如大二进制避免大对象撑爆普通多块载体。对每种结构仪表盘都提供UsedBlock / Carrier与Unused两类视图Block块级已使用内存usageblocks_size即真正被对象占用的部分。Carrier载体级已使用内存usagecarriers_size即向操作系统申请的内存总量。Unused载体与块之间的差值即尚未分配出去的余量。载体是理解“RSS 为什么降不下来”的关键Erlang 虚拟机向操作系统申请到的 Carrier 通常不会立即归还即使内部块已释放Carrier 仍可能被保留复用这会导致 RSS 高于实际 Used。通过 Carrier 与 Block 两条曲线的“开口”可以直观判断内存是被真正占用还是处于待复用状态。五、指标数据来源erlang_vm_allocators 与标签体系该仪表盘全部分配器数据均来自 Prometheus 指标erlang_vm_allocators。在 metrics.md 中的定义如下Allocated (carriers_size) and used (blocks_size) memory for the different allocators in the VM. See erts_alloc(3).该指标带有以下关键标签组合仪表盘正是围绕它们组织面板的标签取值示例含义allocbinary_alloc、ets_alloc、std_alloc等分配器类型kindmbcs、mbcs_pool、sbcs分配结构多块 / 多块池 / 单块usageblocks_size、carriers_size、blocks、carriers内存口径块/载体的“已用字节”与“数量”其中blocks_size/carriers_size用于字节维度的内存占用blocks/carriers用于对象数量维度。仪表盘中“Carrier 平均大小”“Block 平均大小”等面板如sum(... usagecarriers_size) / sum(... usagecarriers)形式的查询正是基于这一标签设计实现的。RSS 与分配器数据的采集均由rabbitmq-prometheus插件完成——该插件自RabbitMQ v3.8.0起随主发行版内置无需额外安装启用后即可在节点 HTTP API 的/metrics端点暴露上述指标。六、过滤维度集群、节点与分配器仪表盘提供三层核心过滤能力RabbitMQ Cluster通过rabbitmq_identity_info的rabbitmq_cluster标签选择目标集群RabbitMQ Node通过rabbitmq_node标签在集群内选择具体节点Erlang Memory Allocator模板变量$memory_allocator支持多值选择并包含 “All” 选项可在同一面板内对比多个分配器的曲线JSON 中的alloc~$memory_allocator正则匹配即服务于该变量。集群/节点过滤的实现机制值得注意erlang_vm_allocators与rabbitmq_process_resident_memory_bytes本身是单节点指标仪表盘通过* on(instance, job) group_left(...) rabbitmq_identity_info{...}将实例身份映射为集群/节点标签从而在混部了多个集群的 Prometheus 中实现精确隔离。这也是 rabbitmq-prometheus 相对早期第三方 exporter 的核心改进之一。七、快速开始三步在本地点亮内存分配器监控要在本地复现该仪表盘只需三步1. 确保 rabbitmq-prometheus 插件已启用。该插件自 RabbitMQ v3.8.0 起为内置插件。启用后节点会在15692端口prometheus.tcp.port默认暴露/metrics端点若使用rabbitmq_prometheus官方 Docker 镜像或本地已启用插件可直接验证curl localhost:15692/metrics | grep erlang_vm_allocators。2. 让 Prometheus 抓取该端点。在 Prometheus 配置的scrape_configs中加入对 RabbitMQ 节点15692端口的抓取任务job 名可自定义仪表盘按instance/job做标签关联。3. 导入仪表盘。在 Grafana 中导入 Erlang-Memory-Allocators.jsonDashboard ID 11350选择 Prometheus 数据源JSON 中的DS_PROMETHEUS输入项并填入namespace、endpoint等模板变量即可。仪表盘要求 Grafana 11.2.2 及以上版本面板类型包含 Stat、Table 与 Time series。仓库还提供了完整的本地演示环境从deps/rabbitmq_prometheus目录执行make overview metrics即可拉起包含 Prometheus、Grafana 与示例工作负载的 docker-compose 栈见 docker/grafana/README.mdlocalhost:3000以admin/admin登录即可看到带真实数据的仪表盘结束后执行make down清理。八、仪表盘的维护与二次开发流程该仪表盘由官方维护改动流程在 docker/grafana/README.md 中有完整说明可供参考在rabbitmq_prometheus目录运行make overview metrics启动本地开发环境在 Grafana UIlocalhost:3000中编辑仪表盘通过 Share → Export勾选Export for sharing externally将 JSON 覆盖写回 dashboards/Erlang-Memory-Allocators.json通过修改 docker-compose-metrics.yml 中services.grafana.image的版本来验证不同 Grafana 版本的兼容性仪表盘的发布说明即本文所依据的文档与截图存放在 docker/grafana/publish/ 目录。九、总结从指标到排障思路Erlang-Memory-Allocators 仪表盘提供了一条完整的内存排障路径先看 RSS 是否逼近内存高水位再通过 Allocated 的 Total/Used/Unused 判断是真实占用还是预分配余量接着按binary_alloc、ets_alloc、eheap_alloc、std_alloc等分配器定位内存去向最后用 Multiblock / Multiblock Pool / Singleblock 的 Block 与 Carrier 曲线判断碎片化与载体复用情况。配合 metrics.md 中的完整指标清单可以进一步结合 GC 回收、I/O 读写、消息存储等指标交叉验证内存增长的根因。这套基于erlang_vm_allocators与rabbitmq_process_resident_memory_bytes的可观测体系让 Erlang VM 这座“黑盒”在 Prometheus Grafana 生态中变得透明可查。【免费下载链接】rabbitmq-serverOpen source RabbitMQ: core server and tier 1 (built-in) plugins项目地址: https://gitcode.com/gh_mirrors/ra/rabbitmq-server创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考