Skip to content

性能调优 ​

性能调优的第一步不是改参数,是确认瓶颈在哪。Producer 慢、Broker 慢、Consumer 慢,调法完全不同,盲调参数常常是负优化。这一章讲每个参数「为什么调、调到什么值、要付出什么代价」。

1. 先定位瓶颈 ​

调优之前先回答一个问题,现在慢在哪一层。

txt
Producer 慢 → 查 Confirm 策略和发送方式
Broker 慢   → 查队列类型、内存水位、磁盘 IO
Consumer 慢 → 查 prefetch、处理逻辑、并发数

三层都调一遍不如先定位一层。用 rabbitmqctl list_queues 看 messages_ready、messages_unacknowledged 和发布、消费速率,用压测看吞吐拐点,确认瓶颈后再动参数。

2. Broker 端资源告警 ​

Broker 端参数很多,其中内存水位和磁盘可用空间阈值直接决定节点何时触发资源告警、阻塞发布连接。它们保护节点不被打爆,但不直接提高消息处理能力,先确认告警或资源限制确实在影响吞吐再动。

vm_memory_high_watermark。内存告警触发阈值,RabbitMQ 4.3 默认相对值为 0.6,即可用内存的 60%(3.x 默认 0.4)。容器环境建议用绝对阈值 vm_memory_high_watermark.absolute,避免相对值受宿主机内存干扰。

为什么要调。达到阈值后,节点触发内存告警并阻塞所有发布连接,直到告警解除。调高水位只是推迟流控触发时间,不会提高消费者处理能力,也消不掉持续增长的消息堆积。

代价。水位过高让 broker 更靠近物理内存极限,一旦有突增流量,操作系统更可能触发 OOM killer。所以调高水位的正确前提是,确认队列堆积能被消费消化掉,而不是堆积永远涨。堆积消不掉时,调高水位只是把崩溃时间推迟。

disk_free_limit。磁盘剩余空间告警阈值,默认 50MB,这个值适合开发和教程环境,生产必须调大。

为什么要调。磁盘告警一旦触发,broker 会阻塞所有发布连接。默认 50MB 意味着磁盘只剩 50MB 才告警,从告警到写满几乎没有反应时间。

代价。调大等于牺牲一部分磁盘空间换取提前量。官方建议阈值下限与内存水位相当,例如节点内存水位设为 4GB 时,disk_free_limit 建议至少 4G,更稳妥可到 6G。但也不是越大越好,阈值过高会过早触发流控、压缩可用写入空间,具体值要结合磁盘容量、写入速率和故障处理时间定。

3. Producer 端 ​

优化项方法前提与代价
异步 Confirm异步回调处理确认,或批量发布后统一等待确认减少逐条等待的空闲;需关联确认结果、处理 Nack 和连接异常,并控制在途消息数量
批量发送累积一批再发提升吞吐,代价是延迟变高,实时性敏感的场景不适用
多 Channel每个并发发布任务一个 ChannelChannel 本身很轻,但别在单连接上无界创建
连接复用多线程共享一个 ConnectionConnection 建立成本高,适合复用;Channel 不应被多线程无保护并发使用

Producer 端优化的主线是减少不必要的同步等待。每发布一条就等一次确认,发布速率会受确认往返延迟限制,改成异步确认或批量发布后统一等待确认都能摊销这个等待。要区分 Publisher Confirm 和 Consumer ACK,前者只说明 broker 已对消息承担投递责任,不代表消费者已经处理成功。

4. Consumer 端 ​

优化项方法前提与代价
调整 prefetch从较小值压测,逐步增加未确认投递上限太小吞吐低,太大增加客户端资源占用、消息等待时间和重投规模
批量 ACK一批处理成功后按同 Channel 的 delivery tag 批量确认减少确认帧开销;ACK 前崩溃会重投,要有幂等
多消费者增加消费者数量受 CPU 核数和下游瓶颈限制,不是越多越好
异步处理消费者内部异步 IO提升单消费者吞吐,但 ACK 时机变难控制,且依赖下游并发能力

Consumer 端的主线是减少无效等待,同时避免超过下游处理能力。prefetch 限制消费者尚未确认的投递数量,太小消费者等消息,太大客户端资源占用和消息等待时间都会增加。没有固定的最优倍数,从较小值开始压测,观察吞吐、内存和未确认数量逐步调大。

5. Queue 选型 ​

Queue 类型存储与可靠性适用场景
Classic单副本,可按需持久化不需要队列复制和高可用保障的工作负载
Quorum基于 Raft 的持久化复制队列需要高可用和数据安全保障的关键业务队列
Stream追加写、可重复读取日志型、事件流、需要重放或多个独立消费者重复读取

选型先确定可靠性要求和消费模式,再比实际性能。需要复制和高可用优先评估 Quorum,不需要复制可评估 Classic,需要重放或重复读取评估 Stream。三种队列的性能不能只用一个延迟数字或吞吐等级比较,消息大小、持久化、确认策略、副本数和磁盘性能都会改变结果。选型是在可靠性要求和性能目标之间做取舍,但这不是固定的三选二,应在满足可靠性要求的前提下用接近生产环境的负载对比。

6. 压测方法 ​

bash
bin/runjava com.rabbitmq.perf.PerfTest \
  -h amqp://localhost \
  -x 5 -y 5 \
  -u test.queue \
  -a \
  --quorum-queue \
  --rate 10000

这是 Quorum Queue 的一个测试起点,不是生产性能基准。压测前先固定队列类型、消息大小、持久化属性、Confirm 与 ACK 策略,再从较低并发逐步增加发布者和消费者,每轮保持其他条件不变,记录发布速率、消费速率、队列堆积、端到端延迟、未确认数量和 Broker 的 CPU、内存、磁盘 IO。

压测要测出拐点,不是测出最高分。找到吞吐不再随并发上升的那个点,结合资源指标判断瓶颈在哪一层,而不是直接继续加线程。参数调整后用相同负载复测,吞吐没改善或延迟、资源消耗恶化,就恢复原配置继续定位。

Released under the MIT License.