RabbitMQ--消费端单线程与多线程

🌟 一、基础概念

模型消费者数量每个消费者内部线程数顺序性场景说明
单消费者单线程11✅ 保序处理逻辑简单,保证顺序的常见场景
单消费者多线程1>1❌ 不保序提升处理能力,放弃顺序要求
多消费者单线程>11❌ 不保序多个队列/分区消费,提升并发
多消费者多线程>1>1❌ 不保序高并发场景下批量处理,放弃顺序


        concurrency# 初始消费者线程数
        max-concurrency# 最大消费者线程数
        prefetch# 每个消费者预取的消息数
  1. concurrency: 2

    • 表示初始创建的消费者线程数量

    • 系统启动时会立即创建 2 个消费者线程

    • 这些线程会持续监听消息队列

  2. max-concurrency: 2

    • 表示允许的最大消费者线程数量

    • 这里设置为 2(与 concurrency 相同),表示线程数不会动态扩展

    • 如果设置 max-concurrency > concurrency,系统会在负载高时动态增加消费者

详细解释:

       concurrency和max-concurrency不会影响每个消费者是否是多线程执行,只会导致有多个消费者线程,只有用线程池才会导致每个消费者多线程消费

        而没有用线程池,也设置prefetch是因为消息被大量预取,单线程处理不过来时堆积等待,单线程并不会影响消息的顺序性,只有使用了线程池才会影响

        使用了线程池一定会导致消息顺序性问题这与设不设置prefetch无关,因为使用线程池后,任务交个线程池就返回了属于异步

        举个例子:

                1. RabbitMQ 给消费者推送消息1,消费者收到,提交给线程池任务A(耗时长)。

                2. 消费者马上ACK消息1(因为业务交给线程池了,自己处理完毕的感觉

                3.  RabbitMQ 再给消费者推送消息2,消费者收到,提交给线程池任务B(耗时短)。

                4. R线程池调度先跑完任务B,后跑任务A。

✅ 单消费者 + 单线程消费

  • 保证顺序:消费者内部串行执行。

  • 配置关键

    spring:
      rabbitmq:
        listener:
          simple:
            concurrency: 1
            max-concurrency: 1
            prefetch: 1
    

  • 消费者代码

    @Component
    public class MultiConsumerSingleThread {
    
        @RabbitListener(queues = "order_queue", concurrency = "2")
        public void receive(String message) {
            System.out.println("🧾 [线程:" + Thread.currentThread().getName() + "] 收到消息:" + message);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    


❌ 单消费者 + 多线程消费

  • 不保顺序:一个消费者使用线程池异步处理消息。

  • 配置关键:默认配置 + 手动异步处理

  • 消费者代码

    @Component
    public class MultiThreadConsumer {
    
        private final ExecutorService executor = Executors.newFixedThreadPool(5);
    
        @RabbitListener(queues = "order_queue")
        public void receive(String message) {
            executor.submit(() -> {
                System.out.println("🧾 [线程:" + Thread.currentThread().getName() + "] 收到消息:" + message);
                try {
                    Thread.sleep(500); // 模拟耗时
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
    }
    
  • 说明:消息提交到线程池,先到的不一定先处理完成,顺序可能乱。


❌ 多消费者 + 单线程消费

  • 不保顺序:多个消费者实例轮询分配消息,各自顺序保留,但整体顺序错乱。

  • 配置关键

    spring:
      rabbitmq:
        listener:
          simple:
            concurrency: 2
            max-concurrency: 2
            prefetch: 1
    

  • 消费者代码(共享类,也可拆成多个类模拟多实例)

    @Component
    public class MultiConsumerSingleThread {
        //concurrency = "2":它和配置文件中的 concurrency: 2 作用一致,但优先级更高。
        @RabbitListener(queues = "order_queue", concurrency = "2")
        public void receive(String message) {
            System.out.println("🧾 [线程:" + Thread.currentThread().getName() + "] 收到消息:" + message);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    

❌ 多消费者 + 多线程消费

  • 不保顺序:每个消费者又使用线程池异步处理消息,最大吞吐量模式。

  • 适合场景:数据导入、日志收集、发送通知等对顺序无要求的批量处理。

  • 配置关键

    spring:
      rabbitmq:
        listener:
          simple:
            concurrency: 3
            max-concurrency: 3
            prefetch: 10
    

  • 消费者代码

    @Component
    public class MultiConsumerMultiThread {
    
        private final ExecutorService executor = Executors.newFixedThreadPool(10);
    
        @RabbitListener(queues = "order_queue", concurrency = "3")
        public void receive(String message) {
            executor.submit(() -> {
                System.out.println("🧾 [线程:" + Thread.currentThread().getName() + "] 收到消息:" + message);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
    }
    

🧠 补充说明

  • concurrency: 控制并发消费者数量,等于消费者数。

  • prefetch: 控制每个消费者本地最多拉取多少条消息(如 1 表示严格串行处理)。

  • 每个 @RabbitListener 本质上是一个容器,可以通过 concurrency 配置“实例个数”。

### RabbitMQ消费者线程模型 在 RabbitMQ 中,消费者的处理方式取决于应用程序如何配置和实现消费逻辑。当创建一个新的 `Channel` 并调用诸如 `basicConsume` 方法时,会启动一个用于接收消息的消费者实例[^1]。 对于每个 Channel 上注册的消费者而言,默认情况下并不是单一线程来处理所有传入的消息。相反,在同一连接下的不同 Channels 可能由不同的操作系统线程负责监听来自服务器的通知并分发给相应的回调函数执行业务逻辑。这意味着即使是在同一个物理 TCP 连接上建立起来的多个 Channels 也可以并发地处理各自收到的任务项[^2]。 然而需要注意的是,虽然可以有多个 Consumers 同时运行在一个 Connection 下的不同 Channels 上,但对于特定 Consumer 来说其内部确实是以串行的方式逐条确认已成功处理过的每一条 Message——即每次只有一条未被应答的消息处于待处理状态直到它完成之后才会继续拉取下一批数据进入内存缓冲区等待进一步操作[^3]。 因此可以说: - **不是严格意义上的单线程模型**:因为可以在多核 CPU 或者分布式环境中通过开启更多 Connections/Channels 实现真正的并行化; - **但就单一 Consumer 而言又是相对独立且有序的一系列事件驱动过程**,这有助于简化编程复杂度同时也保证了一定程度上的事务一致性[^4]。 ```csharp // C# 示例代码展示如何设置基本消费者 var consumer = new EventingBasicConsumer(channel); consumer.Received += (model, ea) => { var body = ea.Body.ToArray(); string message = Encoding.UTF8.GetString(body); Console.WriteLine($"Received {message}"); }; channel.BasicConsume(queue: "queue_name", autoAck: true, consumer: consumer); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值