必须手动ACK并设置prefetchCount,否则限流失效;prefetch是每个消费者线程的未确认消息上限,需与实际处理能力(如DB连接数、单线程吞吐)对齐,且须配合x-max-length等队列策略防OOM。
必须手动 ack + 设置 prefetchcount,否则限流完全失效。 其他配置再全,只要 acknowledge-mode 是 auto 或没配,rabbitmq 就会把消息一股脑全推给消费者,削峰就变成“堆峰”。
为什么 prefetch 不生效?
常见现象:队列积压几十万条,消费者 CPU 和内存飙升,日志里频繁出现 RejectedExecutionException 或 OutOfMemoryError。
-
prefetch是每个消费者线程的限制,不是整个应用。比如concurrency: 5且prefetch: 10,Broker 最多同时向该应用推送 50 条未确认消息 - 如果
acknowledge-mode没设成manual,Spring Boot 默认用auto,消息一送达就自动 ACK,prefetch形同虚设 -
prefetch值过大(如设成 1000)或过小(如设成 1)都会出问题:前者起不到缓冲作用,后者导致吞吐骤降、连接频繁重连
acknowledge-mode: manual 怎么写才安全?
手动 ACK 不是加个配置就完事,业务代码里必须显式调用 channel.basicAck(),且不能漏掉异常分支。
RabbitMQ 4.2.3 是 2026 年初发布的重要稳定更新版本,重点修复了 Khepri 元数据存储相关问题,并改进了监控性能。对于使用 Docker、Kubernetes 或微服务架构的开发团队来说,该版本兼容性和稳定性表现较好。
- 消费方法签名必须带
Channel参数:public void handleMessage(String msg, Channel channel, Message message) - 成功处理后调用
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false) - 捕获所有异常(包括
RuntimeException),并在 catch 块中调用channel.basicNack(..., true)或basicReject(..., true),避免消息卡死 - 不要在 try-catch 外层包一层全局事务(如
@Transactional),否则 ACK 可能被回滚,消息重复投递
队列长度和溢出策略怎么防 OOM?
不设上限的队列在流量洪峰时会吃光磁盘或内存,尤其当消费者短暂不可用时。
- 声明队列时加
x-max-length: 100000(单位:条),硬性限制总容量 - 配套设
x-overflow: drop-head,新消息进来时丢弃最老的一条,避免堆积雪崩 - 避免用
drop-tail(丢新)——它会让最新请求失败,违背削峰“保核心”的初衷 - 如果业务允许延迟,可配合
x-message-ttl自动清理超时消息,但注意 TTL 是 per-message,不是队列级
真正难的不是配参数,而是让 prefetch 和实际处理能力对齐:比如你单线程每秒最多处理 8 条,那 prefetch: 10 是合理值;但如果数据库连接池只有 5 个,而每条消息都要占一个连接,那 prefetch 超过 5 就必然触发连接等待,反而拖慢整体速率。这个平衡点得靠压测找,不是看文档抄出来的。

















