必须手动ack且prefetchcount设为每消费者线程的未确认消息上限才生效;global必须为false,否则rabbitmq静默忽略;prefetch是单channel限额,非应用全局,需按concurrency×prefetch预估内存占用。

prefetchCount 必须配合 manual ack 才生效
设置 prefetchCount 后发现限流没起作用?大概率是启用了自动 ACK。RabbitMQ 的 QoS 机制只在手动确认模式下工作:只要有一条消息没 ack,Broker 就不会推送新消息。自动 ACK 下,消息一送达即标记为完成,prefetchCount 完全被忽略。
确保配置中明确关闭自动应答:
spring:
rabbitmq:
listener:
simple:
acknowledge-mode: manual
Java 配置里也要对应设为 manual,不能依赖默认值。
global=false 是 RabbitMQ 实际生效的唯一模式
RabbitMQ 对 AMQP 协议中 basic.qos 的 global 参数做了限制:只支持 global=false(即 per-consumer 级别)。如果 Spring AMQP 配置里传了 global=true,RabbitMQ 会静默忽略该设置,导致限流失效且无报错。
Spring AMQP 默认就是 global=false,所以通常不用显式设置。但如果你在自定义 Channel 调用 basicQos,务必传 false:
channel.basicQos(10, false); // ✅ 正确
channel.basicQos(10, true); // ❌ RabbitMQ 不认,限流不生效
prefetchCount 是每个 consumer Channel 的未确认上限
prefetchCount 控制的是「单个消费者实例绑定的 Channel」最多持有几条未 ack 的消息,不是整个应用或队列的总量。例如:
- 一个
@RabbitListener方法,默认启动 1 个 consumer,对应 1 个 Channel → 受该prefetchCount约束 - 若配置
concurrent-consumers: 3,则启动 3 个独立 consumer,每个都拥有自己独立的prefetchCount配额 - 内存占用按
prefetchCount × 并发数累加,比如prefetch=50+concurrency=10≈ 最多缓存 500 条消息在 JVM 堆中
局部配置会覆盖全局配置,但要注意作用域
你可以在两个地方设 prefetchCount:
- 全局:通过
SimpleRabbitListenerContainerFactory.setPrefetchCount(),影响所有未显式覆盖的监听器 - 局部:在
@RabbitListener上加prefetch = 1,仅对该监听器生效
注意:局部配置只对当前注解有效,不会影响同一工厂下其他监听器;但如果该监听器启用了 batch="true",prefetch 控制的是批量拉取前的预取窗口,和批大小(max-messages-per-queue)是两回事,别混用。
真正容易被忽略的是:prefetchCount 不是“一次拉多少”,而是“最多留多少在手里没确认”——它卡的是信用余额,不是取件动作本身。这个信用机制决定了消息流速,也决定了消费者崩溃时可能丢失多少未确认消息。










