rabbitmq本身无内存泄漏,但连接未关闭、unacknowledged消息堆积、延迟插件配置失当、tls握手缓存未清理等会导致内存持续占用不释放;需重点监控erlang:memory(processes)、ets_memory和messages_unacknowledged。

RabbitMQ本身不会“内存泄漏”,但连接、未确认消息、插件配置不当或客户端资源未释放,会持续占用内存且不自动回收——这在效果上等同于泄漏。
连接未关闭导致Erlang进程堆积
每个 connection 在 RabbitMQ 中对应一个 Erlang 进程,基础内存约 2–4KB;若客户端每次发完消息就新建 connection 和 channel,却不调用 channel.close() 和 connection.close(),这些进程就会滞留。
- 典型现象:
rabbitmqctl list_connections显示连接数持续上涨,erlang:memory(processes)占比远超erlang:memory(used)其他部分 - 致命顺序:必须先关
channel,再关connection;反序会导致channel异常残留 - Java/Spring AMQP 用户注意:
CachingConnectionFactory默认启用缓存,但若配置了多个ConnectionFactory实例却没复用,仍会重复建连
Unacknowledged 消息长期驻留内存
RabbitMQ 不会对未确认(Unacknowledged)消息设超时。只要消费者连着、没发 basic.ack,哪怕处理逻辑卡死或静默失败,消息就一直锁在内存里(尤其非持久化队列)。
RabbitMQ 4.2.3 是 2026 年初发布的重要稳定更新版本,重点修复了 Khepri 元数据存储相关问题,并改进了监控性能。对于使用 Docker、Kubernetes 或微服务架构的开发团队来说,该版本兼容性和稳定性表现较好。
- 检查命令:
rabbitmqctl list_queues name messages_unacknowledged,重点关注数值 > 1000 的队列 - 风险场景:消费者 catch 了异常但没 re-throw,也未显式
nack或reject,更未发送ack - 默认预取值(
prefetch_count)设得过大(如 1000+),会让大量消息一次性进入未确认状态,加剧内存压力
延迟插件(rabbitmq_delayed_message_exchange)配置失当
该插件内部用 ETS 表存储延迟消息元数据,若未限制 TTL 或分片不足,ETS 内存会随消息量线性增长且不释放。
- 关键参数必须显式配置:
delayed_message.default_message_ttl(避免永不过期)、delayed_message.exchange_shards(建议 ≥4,防单表膨胀) - 监控重点不是队列长度,而是
ets_memory:用rabbitmqctl eval 'erlang:memory(ets).'查看,超过 500MB 就需干预 - 插件启用后,所有延迟消息必须带
x-delay或x-message-ttl,否则退化为普通投递,但元数据仍走延迟路径,造成隐性开销
TLS 握手与证书缓存未清理
启用 TLS 后,每次新连接都会触发完整握手;Erlang SSL 模块会缓存证书链解析结果、OCSP 响应和 session ticket——这些缓存不随连接关闭自动清除,尤其在频繁建连场景下快速累积。
- 现象:连接数不高,但
ssl_handshake相关进程内存持续上升,rabbitmqctl eval 'application:get_env(ssl, session_cache_servers)'返回非空列表 - 缓解方式:在
rabbitmq.conf中设置ssl_options.session_cache = {none, 0}禁用服务端会话缓存(依赖客户端支持 RFC 5077) - 更稳妥做法:改用连接池复用 TLS 连接,而非每次新建;避免在短生命周期任务中启 TLS
真正棘手的不是某一项单独超标,而是多因素叠加:比如客户端一边疯狂建连,一边消费慢导致大量 Unacknowledged,再叠加上延迟插件未设 TTL——这时内存增长会呈指数级,且常规 GC 几乎无效。盯住 erlang:memory(processes)、ets_memory 和 messages_unacknowledged 这三个数字,比看总内存使用率更能定位根因。










