RabbitMQ知识梳理(1)

作者:没有四次元口袋的蓝胖

日期:2026-10-16

标签:RabbitMQ, 安装, HelloWorld, 工作模型

RabbitMQ知识梳理(1)

写在前面

这篇博客带你完成:

  1. RabbitMQ 安装(Docker 一键部署)
  2. 核心概念(端口、虚拟主机、用户权限)
  3. HelloWorld 模型(最简单的 1 对 1 消息传递)
  4. 工作模型(任务分发、能者多劳、持久化)

一、RabbitMQ安装

1.1 Docker安装(推荐)

bash 复制代码
# 拉取镜像(带管理界面)
docker pull rabbitmq:3.12-management

# 启动容器
docker run -d \
  --name rabbitmq \
  -p 5672:5672 \
  -p 15672:15672 \
  -e RABBITMQ_DEFAULT_USER=admin \
  -e RABBITMQ_DEFAULT_PASS=admin123 \
  rabbitmq:3.12-management

端口说明:

  • 5672: 生产者/消费者通信端口(AMQP 协议)
  • 15672: 管理界面端口(HTTP)

访问管理界面:

复制代码
http://localhost:15672
用户名:admin
密码:admin123

1.2 核心配置

虚拟主机(Virtual Host)

作用: 逻辑隔离,不同项目使用不同的 vhost,互不干扰。

bash 复制代码
# 创建虚拟主机
docker exec -it rabbitmq rabbitmqctl add_vhost /myapp

# 查看虚拟主机
docker exec -it rabbitmq rabbitmqctl list_vhosts
用户与权限
bash 复制代码
# 创建用户
docker exec -it rabbitmq rabbitmqctl add_user myuser mypassword

# 设置用户角色(administrator/monitoring/management/policymaker/none)
docker exec -it rabbitmq rabbitmqctl set_user_tags myuser administrator

# 授权用户访问虚拟主机
docker exec -it rabbitmq rabbitmqctl set_permissions -p /myapp myuser ".*" ".*" ".*"

权限说明:

  • 第一个 ".*":配置权限(exchange、queue 的创建)
  • 第二个 ".*":写权限(发送消息)
  • 第三个 ".*":读权限(消费消息)

1.3 SpringBoot集成

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
yaml 复制代码
spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: admin
    password: admin123
    virtual-host: /  # 默认虚拟主机

二、HelloWorld模型

2.1 模型说明

最简单的 1 对 1 模型:

复制代码
生产者 → 队列 → 消费者

核心组件:

  • Queue: 存储消息的队列
  • Producer: 发送消息到队列
  • Consumer: 从队列接收消息

2.2 创建队列

java 复制代码
@Configuration
public class RabbitConfig {
    
    /**
     * 创建队列
     * durable: 是否持久化(重启后队列还在)
     * exclusive: 是否独占(只有当前连接可用)
     * autoDelete: 是否自动删除(没有消费者时删除)
     */
    @Bean
    public Queue helloQueue() {
        return new Queue("hello.queue", true);  // true = 持久化
    }
}

2.3 生产者

java 复制代码
@Component
public class HelloProducer {
    
    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    public void sendMessage(String message) {
        // 发送消息到队列
        rabbitTemplate.convertAndSend("hello.queue", message);
        System.out.println("发送消息: " + message);
    }
}

2.4 消费者

java 复制代码
@Component
@RabbitListener(queues = "hello.queue")
public class HelloConsumer {
    
    @RabbitHandler
    public void receiveMessage(String message) {
        System.out.println("收到消息: " + message);
    }
}

2.5 测试

java 复制代码
@SpringBootTest
public class RabbitTest {
    
    @Autowired
    private HelloProducer helloProducer;
    
    @Test
    public void testHelloWorld() throws InterruptedException {
        helloProducer.sendMessage("Hello, RabbitMQ!");
        helloProducer.sendMessage("Hello, 蓝胖!");
        
        Thread.sleep(1000);  // 等待消费者处理
    }
}

输出:

复制代码
发送消息: Hello, RabbitMQ!
发送消息: Hello, 蓝胖!
收到消息: Hello, RabbitMQ!
收到消息: Hello, 蓝胖!

三、工作模型(Work Queues)

3.1 模型说明

任务分发模型: 一个生产者,多个消费者,消息按轮询分发。

复制代码
        ┌→ 消费者A
生产者 → 队列 →├→ 消费者B
        └→ 消费者C

适用场景: 任务分发、负载均衡。

3.2 代码实现

生产者
java 复制代码
@Component
public class WorkProducer {
    
    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    public void sendTask(String task) {
        rabbitTemplate.convertAndSend("work.queue", task);
        System.out.println("发送任务: " + task);
    }
}
消费者
java 复制代码
@Component
public class WorkConsumer {
    
    @RabbitListener(queues = "work.queue")
    public void consumerA(String task) {
        System.out.println("消费者A 收到任务: " + task);
        try {
            Thread.sleep(1000);  // 模拟耗时操作
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("消费者A 完成任务: " + task);
    }
    
    @RabbitListener(queues = "work.queue")
    public void consumerB(String task) {
        System.out.println("消费者B 收到任务: " + task);
        try {
            Thread.sleep(2000);  // 模拟耗时操作(比A慢)
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("消费者B 完成任务: " + task);
    }
}
测试
java 复制代码
@Test
public void testWorkModel() throws InterruptedException {
    for (int i = 1; i <= 4; i++) {
        workProducer.sendTask("任务" + i);
    }
    Thread.sleep(10000);
}

输出(轮询分发):

复制代码
发送任务: 任务1
发送任务: 任务2
发送任务: 任务3
发送任务: 任务4

消费者A 收到任务: 任务1
消费者B 收到任务: 任务2
消费者A 收到任务: 任务3  (A先完成,继续接收任务3)
消费者B 收到任务: 任务4  (B后完成,接收任务4)

消费者A 完成任务: 任务1
消费者A 完成任务: 任务3
消费者B 完成任务: 任务2
消费者B 完成任务: 任务4

3.3 能者多劳(Fair Dispatch)

问题: 默认轮询分发,不管消费者处理速度。如果消费者A很快(1秒),消费者B很慢(2秒),A会闲置。

解决: 配置 basicQos,每次只发一条消息,处理完再发下一条。

java 复制代码
@Configuration
public class RabbitConfig {
    
    @Bean
    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(
            SimpleRabbitListenerContainerFactoryConfigurer configurer,
            ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        configurer.configure(factory, connectionFactory);
        
        // 每次只预取1条消息(能者多劳)
        factory.setPrefetchCount(1);
        
        return factory;
    }
}

效果:

复制代码
消费者A 收到任务: 任务1
消费者B 收到任务: 任务2

消费者A 完成任务: 任务1(1秒后)
消费者A 收到任务: 任务3  (A先完成,立即接收任务3)

消费者B 完成任务: 任务2(2秒后)
消费者B 收到任务: 任务4

消费者A 完成任务: 任务3
消费者B 完成任务: 任务4

对比:

模式 分发策略 性能
轮询 平均分配 A 闲置,B 忙碌
能者多劳 按处理能力 A 处理 3 个,B 处理 1 个

3.4 消息持久化

问题: RabbitMQ 重启后,队列中的消息会丢失。

解决: 队列和消息都开启持久化。

队列持久化
java 复制代码
@Bean
public Queue workQueue() {
    return new Queue("work.queue", true);  // true = 持久化
}
消息持久化
java 复制代码
public void sendTask(String task) {
    // 设置消息为持久化
    MessageProperties props = new MessageProperties();
    props.setDeliveryMode(MessageDeliveryMode.PERSISTENT);  // 持久化
    
    Message message = new Message(task.getBytes(), props);
    rabbitTemplate.send("work.queue", message);
}

注意:

  • 队列持久化:RabbitMQ 重启后队列还在
  • 消息持久化:RabbitMQ 重启后消息还在(需要写入磁盘,性能略降)
  • 如果消息丢失,可能是消费者处理失败但没有 ACK

3.5 手动ACK

问题: 消费者处理消息时抛异常,消息会丢失(默认自动 ACK)。

解决: 手动 ACK,处理成功才确认。

yaml 复制代码
spring:
  rabbitmq:
    listener:
      simple:
        acknowledge-mode: manual  # 手动ACK
java 复制代码
@Component
public class WorkConsumer {
    
    @RabbitListener(queues = "work.queue")
    public void consumerA(Message message, Channel channel) throws Exception {
        String task = new String(message.getBody());
        System.out.println("消费者A 收到任务: " + task);
        
        try {
            // 处理任务
            processTask(task);
            
            // 手动ACK(确认消息已处理)
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            System.out.println("消费者A 完成任务: " + task);
            
        } catch (Exception e) {
            // 处理失败,拒绝消息(requeue = true 重新入队)
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
            System.out.println("消费者A 处理失败,重新入队: " + task);
        }
    }
}

ACK 模式对比:

模式 说明 适用场景
auto 自动 ACK(处理完立即确认) 不关心消息丢失
manual 手动 ACK(代码中确认) 关心消息不丢失
none 不 ACK(消息发出去就不管) 不推荐

四、思维导图速览

复制代码
RabbitMQ安装与HelloWorld模型
├── 安装
│   ├── Docker部署(rabbitmq:3.12-management)
│   ├── 端口:5672(通信)/ 15672(管理界面)
│   ├── 虚拟主机(vhost):逻辑隔离
│   └── 用户权限:配置/写/读
├── HelloWorld模型(1对1)
│   ├── 生产者:rabbitTemplate.convertAndSend()
│   ├── 消费者:@RabbitListener + @RabbitHandler
│   └── 队列:Queue(durable = 持久化)
├── 工作模型(任务分发)
│   ├── 轮询分发(默认)
│   ├── 能者多劳(basicQos = 1)
│   ├── 消息持久化(MessageDeliveryMode.PERSISTENT)
│   └── 手动ACK(basicAck / basicNack)
└── 关键配置
    ├── spring.rabbitmq.listener.simple.acknowledge-mode
    ├── spring.rabbitmq.listener.simple.prefetch
    └── @Bean Queue(durable, exclusive, autoDelete)

五、写在最后

学习建议

  1. 先动手搭建环境

    用 Docker 一键部署 RabbitMQ,登录管理界面看看队列、Exchange 的样子,比看文档更直观。

  2. HelloWorld 是基础

    先跑通最简单的 1 对 1 模型,再学工作模型、发布订阅等高级特性。

  3. 能者多劳是面试高频题

    面试官问你"RabbitMQ 怎么实现负载均衡",直接甩出 basicQos 和公平分发,比说"轮询"更有说服力。

高频面试题总结

问题 核心答案
RabbitMQ的端口有哪些? 5672(AMQP通信)、15672(管理界面)
什么是虚拟主机(vhost)? 逻辑隔离,不同项目用不同vhost,互不干扰
HelloWorld模型是什么? 最简单的1对1模型:生产者→队列→消费者
工作模型的轮询分发有什么问题? 不管消费者处理速度,快的闲置,慢的忙碌
怎么实现能者多劳? 设置prefetchCount=1,每次只发一条,处理完再发
如何保证消息不丢失? 队列持久化 + 消息持久化 + 手动ACK
相关推荐
霸道流氓气质3 小时前
Redisson BloomFilter:分布式位图实现、误判率调优与缓存穿透三级防护的 Spring Boot 生产级实战
spring boot·分布式·缓存
流烟默4 小时前
ClickHouse 集群建表实战:从引擎选择到本地表 / 分布式表落地
分布式·clickhouse
donk131419 小时前
React Native for OpenHarmony 实战:三方库 react-native-step-indicator 的鸿蒙化适配指南
分布式·react native·react.js·wpf·harmonyos
梅菲塔亚21 小时前
Ceph分布式存储
分布式·ceph
acrel71 天前
Acrel-1000系列分布式光伏监控系统在湖北荆门一马光彩大市场屋顶光伏发电项目中应用
分布式·光伏并网
程序 代码狂人1 天前
金融数仓体系与核心业务知识详解
大数据·分布式·spark
java_nnnn1 天前
Redis 初识:从单体架构到分布式架构的演进
redis·分布式·架构
Sayai1 天前
Kafka 2.8→3.9.1 跨大版本升级实战:ZooKeeper 同步升级、数据目录迁移与回滚预案全流程
大数据·运维·分布式·zookeeper·kafka
敲上瘾1 天前
分布式系统——Redis哨兵:自动故障转移与选举原理
linux·数据库·redis·分布式·缓存·微服务