bigywater.tech
RabbitMQ · 14

惰性队列(lazy)与内存

“lazy 队列”曾是对付积压的标准做法:让队列尽量把消息写盘、少占内存。到了 4.x 默认的经典队列又是什么样?x-queue-mode=lazy 还有用吗?quorum 队列的内存账怎么算?这篇用 100000 条消息实际量一遍。

1.3 MiB
100000 条 1 KB 消息放进默认经典队列后 broker 总内存的增量
166.3 MiB
同样数据放进 quorum 队列后 broker 总内存的增量
1 条
两种经典队列(默认与 lazy)堆了 100000 条后,内存里的消息数 messages_ram

lazy 参数

实测 · 本机执行输出
  x-queue-mode=lazy: 声明成功
  x-queue-mode=default: 声明成功
  rabbitmqctl list_queues 里的参数: ['q.default\t[{"x-queue-mode","default"},{"x-queue-type","classic"}]', 'q.lazy\t[{"x-queue-mode","lazy"},{"x-queue-type","classic"}]']
  list_queues 能看到的与内存相关的字段: messages_ram, message_bytes_ram, memory;是否有 queue_mode 一类的字段: False

x-queue-mode=lazy 在 4.3.6 仍能声明,没有报错;但经典队列默认就不再把积压的消息放在内存里,所以带不带这个参数在内存数字上看不出区别。

积压时的内存

实测 · 本机执行输出
  队列               messages  messages_ram  message_bytes_ram  队列进程内存    broker 总内存增量
  classic.default     100000             1           0.0 MiB         0.7 MiB         1.3 MiB
  classic.lazy        100000             1           0.0 MiB         1.1 MiB         1.0 MiB

100000 条 1 KB 的持久化消息(共约 100 MB)放进经典队列,messages_ram 只有 1,broker 总内存只增加 1.0~1.3 MiB。

quorum 队列的账

实测 · 本机执行输出
  quorum.q: messages=100000 messages_ram=0 message_bytes_ram=0.0 MiB 队列进程内存=4.5 MiB broker 总内存增量=166.3 MiB

同样的消息进 quorum 队列,队列进程内存 4.5 MiB,可是 broker 总内存涨了 166.3 MiB;看队列自己的 memory 字段会低估它。

消费时

实测 · 本机执行输出
  消费者确认了 2147 条后: messages=97853 messages_ram=568 message_bytes_ram=0.55 MiB 队列进程内存=2.8 MiB

消费者在线时,内存里只有投递窗口附近的消息(568 条、0.55 MiB),积压的 97853 条仍在磁盘上。

重启

实测 · 本机执行输出
  重启(关闭 + 启动 + await_startup)总共 11.1 s;重启后 classic.default: messages=97853 messages_ram=1 队列进程内存=0.0 MiB
  取 100 条用了 14 ms(重启后消息要从磁盘读)

重启不会把积压的消息整个装进内存:11.1 s 启动后队列里 messages_ram 只有 1,取 100 条用 14 ms 按需读盘。

分步演示

惰性队列
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / RabbitMQ 4.3.6 / Erlang/OTP 28.5 / pika 1.4.4(Homebrew 与临时虚拟环境);所有节点都是本机自己起的 RabbitMQ 进程(127.0.0.1,端口 9500 以上,每个实验独立的数据目录与节点名,不连任何外部服务);命令输出来自真实的 rabbitmqctl 与管理 API,发布与消费用 pika 的真实连接;计时用 time.perf_counter,数字每次运行会有小幅抖动。内存数字来自 rabbitmqctl list_queues(messages_ram、message_bytes_ram、memory)和 rabbitmqctl eval erlang:memory(total).(放入前后的差);每个队列单独放 100000 条 1 KB 持久化消息,等 3 秒再读;第五节计时包含 rabbitmqctl shutdown、重新启动和 await_startup
    • 没有验证:早期版本(3.x)的 lazy 行为对比;内存水位触发流控时经典队列的表现(见第 20 篇);更大的积压(千万级);quorum 队列内存占用随 Raft 日志截断的变化(没有看 166.3 MiB 何时回落);非持久化消息或有消费者时的内存差异;消息体更小时的占用
    京ICP备2026067502号-1京公网安备11010502063487号