prefetch设为0表示禁用预取限制,RabbitMQ会尽可能快地推送所有消息,导致消费者本地缓存(BlockingQueue)默认膨胀至Integer.MAX_VALUE,极易引发OOM或内存抖动,生产环境必须避免。

prefetch 设置为 0 会怎样?
设置 spring.rabbitmq.listener.simple.prefetch=0 表示禁用预取限制,RabbitMQ 会尽可能快地把队列中所有消息推给消费者。这不是“无限制”而是“退化为旧版行为”:每个 consumer 的本地缓存(BlockingQueue)默认大小是 Integer.MAX_VALUE,极易引发 OOM 或内存抖动。生产环境必须避免。
prefetch 和 concurrency 要一起看,不能只调一个
两者作用层面不同:concurrency 控制线程数(容器级),prefetch 控制每条线程能缓存多少未确认消息(channel 级)。实际未确认消息总数 = concurrency × prefetch。
- 比如
concurrency=5、prefetch=10→ 最多 50 条消息卡在消费者内存里没 ACK - 若处理慢(如单条耗时 500ms),这 50 条可能积压 25 秒,而新消息还在不断进队列
- 反过来,若
concurrency=1但prefetch=200,一条线程扛着 200 条消息,CPU 没压满,内存先爆了
按业务耗时选 prefetch 值:别套公式,看实测
官方默认 250 是吞吐优先的通用值,但多数真实业务不适用。关键看单条消息平均处理时间(含 DB、HTTP、计算):
RabbitMQ 4.2.3 是 2026 年初发布的重要稳定更新版本,重点修复了 Khepri 元数据存储相关问题,并改进了监控性能。对于使用 Docker、Kubernetes 或微服务架构的开发团队来说,该版本兼容性和稳定性表现较好。
-
≤ 50ms(日志、埋点类):可设
prefetch=100~200,减少网络往返开销 -
50ms ~ 300ms(常规订单、通知):推荐
prefetch=10~50,平衡吞吐与内存压力 -
> 300ms(报表生成、图像处理):强制
prefetch=1,否则慢消费者会“囤货”,快消费者空转
注意:prefetch=1 必须配合手动 ACK(acknowledge-mode: manual),否则无效。
prefetch=1 时为什么还要配 concurrency?
看起来矛盾,其实解决的是不同维度问题:prefetch=1 保证每条消息都“按需分发”,concurrency 决定有多少个“按需分发”的执行单元同时在线。
- 单 consumer +
prefetch=1:顺序强,但吞吐低,CPU 利用率上不去 - 多 consumer +
prefetch=1:消息被动态调度到空闲线程,负载更均衡,K8s 下多个 Pod 实例也能真正分摊压力 - 典型配置:
concurrency=3-8+prefetch=1+acknowledge-mode: manual
最容易被忽略的一点:prefetch 生效前提是 channel 复用稳定——如果每次消费都新建 channel,QoS 设置会被重置;Spring AMQP 默认复用 channel,但自定义 CachingConnectionFactory 时要确认 cache.channel.size ≥ concurrency,否则 channel 不够用,反而触发重建。

















