简介 
RabbitMQ是一个流行的消息中间件,它基于AMQP协议,提供了一个可靠的消息队列服务。
生产者(Producer):消息的发送方,负责将消息发送到RabbitMQ。 
消费者(Consumer):消息的接收方,从RabbitMQ接收消息并进行处理。 
消息(Message):在RabbitMQ中传输的数据,它由消息头和消息体组成。 
队列(Queue):消息的存储地,生产者发送的消息会被放入队列中,消费者从队列中获取消息。 
交换器(Exchange):接收来自生产者的消息,并将消息根据路由规则发送到一个或多个队列。RabbitMQ支持多种类型的交换器,例如: 
 
直接交换器(Direct Exchange):根据路由键将消息路由到具有匹配路由键的队列。 
主题交换器(Topic Exchange):根据路由键和模式匹配将消息路由到队列。 
扇出交换器(Fanout Exchange):将消息发送到所有绑定的队列,不考虑路由键。 
头交换器(Headers Exchange):根据消息的头属性进行路由。 
 
 
绑定(Binding):交换器和队列之间的虚拟连接,它定义了消息如何从交换器路由到队列。 
虚拟主机(Vhost):RabbitMQ服务器的命名空间,拥有自己的队列、交换器和绑定,可以看作是消息的隔离环境。 
连接(Connection):客户端与RabbitMQ服务器之间的TCP连接。 
通道(Channel):在客户端和RabbitMQ之间的虚拟连接,大多数RabbitMQ操作都在通道上进行,如声明队列、发送和接收消息等。 
持久性(Durability):消息或队列的持久性设置,确保消息或队列在RabbitMQ服务器重启后依然存在。 
确认(Acknowledgement):消费者接收并处理消息后,向RabbitMQ发送的确认信号,表示消息已被成功处理。 
死信队列(Dead Letter Exchange):当消息无法被正常处理时,会被发送到死信队列。 
 
SpringBoot接入RabbitMQ 
点对点(单队列方式) 
该方式只需要我们定义一个队列,然后向队列中发送消息即可,然后消费者监听该队列。
 
        
          
            
            
              yml 
              复制代码 
              
           
          <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>  
      队列设置 
        
          
            
            
              java 
              复制代码 
              
           
          @Configuration
public class SampleConfig {
    public static final String QUEUE = "SAMPLE_QUEUE";
    @Autowired
    private AmqpAdmin amqpAdmin;
    @Bean(QUEUE)
    public Queue sampleQueue(){
        return new Queue(QUEUE);
    }
    public static final String QUEUE2 = "SAMPLE_QUEUE2";
    @Bean(QUEUE2)
    public Queue sampleQueue2(){
        return new Queue(QUEUE2);
    }
}  
      生产者 
        
          
            
            
              java 
              复制代码 
              
           
          @Component
public class SampleProducer {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    public void send(String message){
        rabbitTemplate.convertAndSend(SampleConfig.QUEUE, message);
        rabbitTemplate.convertAndSend(SampleConfig.QUEUE2, message);
    }
}  
      消费者 
消费者,我们也可以定义多个消费者,监听同一个队列,这样就进行了负载均衡,消息会按照顺序消费,生产过程中一般也是这样使用的(只不过是利用的线程池来消费)。
 
        
          
            
            
              java 
              复制代码 
              
           
          @Slf4j
@Component
public class SampleConsumer {
    @RabbitListener(queues = SampleConfig.QUEUE)
    public void fire(String message){
        log.info("收到消息" + message);
    }
    @RabbitListener(queues = SampleConfig.QUEUE)
    public void fire1(String message){
        log.info("收到消息1" + message);
    }
}  
      测试 
        
          
            
            
              java 
              复制代码 
              
           
          @RestController
@RequestMapping(value = "test")
public class TestController {
    @Autowired
    private SampleProducer sampleProducer;
    @GetMapping(value = "sampleProducer")
    public Object sampleProducer(){
        sampleProducer.send("sampleProducer" + System.currentTimeMillis());
        return "SUCCESS";
    }
}  
      发布订阅模式(fanout) 
该模式就像是订阅新闻一样,我喜欢这个新闻,我订阅它,当它更新的时候就会给你推送最新的新闻;该模式需要引入交换机概念。
 
Exchange交换机和Queue队列配置 
        
          
            
            
              java 
              复制代码 
              
           
          @Configuration
public class FanoutConfig {
    public static final String QUEUE_ZS = "collect_zs";
    public static final String QUEUE_LS = "collect_ls";
    public static final String EXCHANGE_COLLECT = "exchange_collect";
    /**
     * 定义交换机
     * @return
     */
    @Bean
    public FanoutExchange fanoutExchangeCollect(){
        return new FanoutExchange(EXCHANGE_COLLECT);
    }
    /**
     * 定义队列
     * @return
     */
    @Bean
    public Queue queueCollectZs(){
        return new Queue(QUEUE_ZS);
    }
    /**
     * 定义队列
     * @return
     */
    @Bean
    public Queue queueCollectLs(){
        return new Queue(QUEUE_LS);
    }
    /**
     * 绑定队列到交换机
     * @param fanoutExchangeCollect
     * @param queueCollectZs
     * @return
     */
    @Bean
    public Binding bindingZs(FanoutExchange fanoutExchangeCollect, Queue queueCollectZs){
        return BindingBuilder.bind(queueCollectZs).to(fanoutExchangeCollect);
    }
    /**
     * 绑定队列到交换机
     * @param fanoutExchangeCollect
     * @param queueCollectLs
     * @return
     */
    @Bean
    public Binding bindingLs(FanoutExchange fanoutExchangeCollect, Queue queueCollectLs){
        return BindingBuilder.bind(queueCollectLs).to(fanoutExchangeCollect);
    }
}  
      生产者 
        
          
            
            
              java 
              复制代码 
              
           
          @Service
public class FanoutProducer {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    /**
     * 发送消息
     * 路由键设置为空字符串
     * @param message
     */
    public void send(String message){
        rabbitTemplate.convertAndSend(FanoutConfig.EXCHANGE_COLLECT, "", message);
    }
}  
      消费者 
        
          
            
            
              java 
              复制代码 
              
           
          @Slf4j
@Service
public class FanoutConsumer {
    @RabbitListener(queues = FanoutConfig.QUEUE_ZS)
    public void fireZs(String message){
        log.info("张三收到消息" + message);
    }
    @RabbitListener(queues = FanoutConfig.QUEUE_LS)
    public void fireLs(String message){
        log.info("李四收到消息" + message);
    }
}  
      测试 
        
          
            
            
              java 
              复制代码 
              
           
          @RestController
@RequestMapping(value = "test")
public class TestController {
    @Autowired
    private FanoutProducer fanoutProducer;
    @GetMapping(value = "fanoutProducer")
    public Object fanoutProducer(String message){
        fanoutProducer.send("fanoutProducer:" + message +  System.currentTimeMillis());
        return "SUCCESS";
    }
}  
      结果 
        
          
            
            
              yaml 
              复制代码 
              
           
          2024-07-11 09:25:19.192  INFO 1572 --- [ntContainer#0-1] c.h.rabbitmq.demo.fanout.FanoutConsumer  : 张三收到消息fanoutProducer:你好1720661119173
2024-07-11 09:25:19.193  INFO 1572 --- [ntContainer#1-1] c.h.rabbitmq.demo.fanout.FanoutConsumer  : 李四收到消息fanoutProducer:你好1720661119173
2024-07-11 09:25:24.485  INFO 1572 --- [ntContainer#0-1] c.h.rabbitmq.demo.fanout.FanoutConsumer  : 张三收到消息fanoutProducer:你好a1720661124482
2024-07-11 09:25:24.492  INFO 1572 --- [ntContainer#1-1] c.h.rabbitmq.demo.fanout.FanoutConsumer  : 李四收到消息fanoutProducer:你好a1720661124482  
      路由选择模式(direct) 
该模式下我们只需要关注我们关心的消息,比如系统发送的日志,普通的日志收集器则需要关注error、info、warning,但是报警服务则只需要关注error级别的日志,下面给出使用案例。
 
Exchange交换机和Queue队列、Routing路由配置 
        
          
            
            
              java 
              复制代码 
              
           
          @Configuration
public class DirectConfig {
    public static final String QUEUE_LOG_ALL = "queue_log_all";
    public static final String QUEUE_LOG_ERROR = "queue_log_error";
    public static final String EXCHANGE_LOG = "log";
    public static final String ROUTING_KEY_INFO = "info";
    public static final String ROUTING_KEY_ERROR = "error";
    /**
     * 定义交换机
     * @return
     */
    @Bean
    public DirectExchange directExchangeLog(){
        return new DirectExchange(EXCHANGE_LOG);
    }
    @Bean
    public Queue queueLogAll(){
        return new Queue(QUEUE_LOG_ALL);
    }
    @Bean
    public Queue queueLogError(){
        return new Queue(QUEUE_LOG_ERROR);
    }
    /**
     * 绑定info的路由键到all队列
     * @param queueLogAll
     * @param directExchangeLog
     * @return
     */
    @Bean
    public Binding bindingInfoToAll(Queue queueLogAll, DirectExchange directExchangeLog){
        return BindingBuilder.bind(queueLogAll).to(directExchangeLog).with(ROUTING_KEY_INFO);
    }
    /**
     * 绑定error的路由键到all队列
     * @param queueLogAll
     * @param directExchangeLog
     * @return
     */
    @Bean
    public Binding bindingErrorToAll(Queue queueLogAll, DirectExchange directExchangeLog){
        return BindingBuilder.bind(queueLogAll).to(directExchangeLog).with(ROUTING_KEY_ERROR);
    }
    /**
     * 绑定error的路由键到error队列
     * @param queueLogError
     * @param directExchangeLog
     * @return
     */
    @Bean
    public Binding bindingErrorToError(Queue queueLogError, DirectExchange directExchangeLog){
        return BindingBuilder.bind(queueLogError).to(directExchangeLog).with(ROUTING_KEY_ERROR);
    }
}  
      生产者 
        
          
            
            
              java 
              复制代码 
              
           
          @Service
public class DirectProducer {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    /**
     * 发送消息
     * @param message
     */
    public void send(String routingKey, String message){
        rabbitTemplate.convertAndSend(DirectConfig.EXCHANGE_LOG, routingKey, message);
    }
}  
      消费者 
        
          
            
            
              java 
              复制代码 
              
           
          @Slf4j
@Service
public class DirectConsumer {
    @RabbitListener(queues = DirectConfig.QUEUE_LOG_ALL)
    public void fireAll(String message){
        log.info("接收所有日志:" + message);
    }
    @RabbitListener(queues = DirectConfig.QUEUE_LOG_ERROR)
    public void fireError(String message){
        log.info("接收ERROR日志:" + message);
    }
}  
      测试 
        
          
            
            
              java 
              复制代码 
              
           
          @RestController
@RequestMapping(value = "test")
public class TestController {
    @Autowired
    private DirectProducer directProducer;
    @GetMapping(value = "directProducer")
    public Object directProducer(String routingKey, String message){
        directProducer.send(routingKey, "directProducer:" + message +  System.currentTimeMillis());
        return "SUCCESS";
    }
}  
      结果 
        
          
            
            
              yaml 
              复制代码 
              
           
          2024-07-11 10:32:48.856  INFO 20856 --- [ntContainer#1-1] c.h.rabbitmq.demo.direct.DirectConsumer  : 接收所有日志:directProducer:info日志1720665168842
2024-07-11 10:32:54.364  INFO 20856 --- [ntContainer#1-1] c.h.rabbitmq.demo.direct.DirectConsumer  : 接收所有日志:directProducer:info日志1720665174363
2024-07-11 10:33:05.009  INFO 20856 --- [ntContainer#1-1] c.h.rabbitmq.demo.direct.DirectConsumer  : 接收所有日志:directProducer:error日志1720665185007
2024-07-11 10:33:05.010  INFO 20856 --- [ntContainer#0-1] c.h.rabbitmq.demo.direct.DirectConsumer  : 接收ERROR日志:directProducer:error日志1720665185007
2024-07-11 10:33:08.103  INFO 20856 --- [ntContainer#0-1] c.h.rabbitmq.demo.direct.DirectConsumer  : 接收ERROR日志:directProducer:error日志1720665188102
2024-07-11 10:33:08.103  INFO 20856 --- [ntContainer#1-1] c.h.rabbitmq.demo.direct.DirectConsumer  : 接收所有日志:directProducer:error日志1720665188102  
      通配符模式Topics 
该模式其实和Direct模式差不多,只不过路由键可以配置为通配符,这样让我们配置更方便简单。下面随便列了使用方式,匹配dog.*路由键和cat.*的路由键。
 
配置类 
        
          
            
            
              java 
              复制代码 
              
           
          @Configuration
public class TopicsConfig {
    public static final String QUEUE_DOG = "dog";
    public static final String QUEUE_CAT = "cat";
    public static final String EXCHANGE_ANIMAL = "animal";
    public static final String ROUTING_KEY_DOG = "dog.*";
    public static final String ROUTING_KEY_CAT = "cat.*";
    @Bean
    public Queue queueDog(){
        return new Queue(QUEUE_DOG);
    }
    @Bean
    public Queue queueCat(){
        return new Queue(QUEUE_CAT);
    }
    @Bean
    public TopicExchange topicExchangeAnimal(){
        return new TopicExchange(EXCHANGE_ANIMAL);
    }
    @Bean
    public Binding bindingDog(Queue queueDog, TopicExchange topicExchangeAnimal){
        return BindingBuilder.bind(queueDog).to(topicExchangeAnimal).with(ROUTING_KEY_DOG);
    }
    @Bean
    public Binding bindingCat(Queue queueCat, TopicExchange topicExchangeAnimal){
        return BindingBuilder.bind(queueCat).to(topicExchangeAnimal).with(ROUTING_KEY_CAT);
    }
}  
      生产者 
        
          
            
            
              java 
              复制代码 
              
           
          @Service
public class TopicsProducer {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    /**
     * 发送消息
     * @param message
     */
    public void send(String routingKey, String message){
        rabbitTemplate.convertAndSend(TopicsConfig.EXCHANGE_ANIMAL, routingKey, message);
    }
}  
      消费者 
        
          
            
            
              java 
              复制代码 
              
           
          @Slf4j
@Service
public class TopicsConsumer {
    @RabbitListener(queues = TopicsConfig.QUEUE_DOG)
    public void fireDog(String message){
        log.info("狗收到消息" + message);
    }
    @RabbitListener(queues = TopicsConfig.QUEUE_CAT)
    public void fireCat(String message){
        log.info("猫收到消息" + message);
    }
}  
      测试 
        
          
            
            
              java 
              复制代码 
              
           
          @RestController
@RequestMapping(value = "test")
public class TestController {
    @Autowired
    private TopicsProducer topicsProducer;
    @GetMapping(value = "topicsProducer")
    public Object topicsProducer(String routingKey, String message){
        topicsProducer.send(routingKey, "topicsProducer:" + message +  System.currentTimeMillis());
        return "SUCCESS";
    }
}  
      结果 
        
          
            
            
              yaml 
              复制代码 
              
           
          2024-07-11 12:47:42.586  INFO 21200 --- [ntContainer#6-1] c.h.rabbitmq.demo.topics.TopicsConsumer  : 狗收到消息topicsProducer:红色的狗1720673262558
2024-07-11 12:47:55.628  INFO 21200 --- [ntContainer#6-1] c.h.rabbitmq.demo.topics.TopicsConsumer  : 狗收到消息topicsProducer:蓝色的狗1720673275621
2024-07-11 12:48:04.502  INFO 21200 --- [ntContainer#7-1] c.h.rabbitmq.demo.topics.TopicsConsumer  : 猫收到消息topicsProducer:蓝色的猫1720673284499  
      进阶 
过期时间TTL 
死信队列 
延迟队列 
消息确认机制 
消息追踪 
常问问题 
消息堆积 
消息丢失 
有序消费消息 
重复消费 
配置 
RabbitMq单机 
RabbitMq集群 
控制台 
RabbitMQ的概览情况,里面包括集群各个节点的信息、端口映射信息。 
1. Overview(概览) 
1.1 Totals(总数) 
1.1.1 Queued messages 
当前Vhost下的所有队列消息情况 
参数 
简述 
 
 
Ready 
准备好的消息数量(生产者生产的消息已经到达Broker,可以让消费者消费的数量)。 
 
Unacked 
全称Unacknowledged,待应答的消息总数。 
 
Total 
Ready和Unacked的数量总和。 
 
 
1.1.2. Message rates 
消息速率 
参数 
简述 
 
 
Publish 
生产者生产消息的速率 
 
Publisher confirm 
broker确认生产消息的速率 
 
Deliver(manual ack) 
customer手动确认的速率 
 
Deliver( auto ack) 
customer自动确认的速率 
 
Consumer ack 
customer正在确认的速率 
 
Redelivered 
正在传递'redelivered'标志集的消息的速率 
 
Get (manual ack) 
响应basic.get而要求确认的消息的传输速率 
 
Get (auto ack) 
响应basic.get而发送不需要确认的消息的速率 
 
Get (empty) 
从队列中获取消息,但队列当前没有可用的消息可供获取。 
 
Return 
将basic.return发送给producter的速率 
 
Disk read 
queue从磁盘读取消息的速率 
 
Disk write 
queue从磁盘写入消息的速率 
 
 
1.1.3. Global counts 
各个组件的总数【统计当前选择的Vhost下的】。 
参数 
简述 
 
 
Connections 
client的tcp连接的总数 
 
Channels 
通道的总数 
 
Exchange 
交换器的总数 
 
Queues 
队列的总数 
 
Consumers 
消费者的总数 
 
 
1.2. Nodes(节点消息) 
启动一个 broker  都会产生一个 node  。 broker的属性 
参数 
简述 
 
 
Name 
broker名称 
 
File descriptors 
broker打开的文件描述符实际数量和限制值。 
 
Socket descriptors 
broker管理的网络套接字数量和限制。当限制被耗尽时,RabbitMQ将停止接受新的网络连接。实际使用值一般略大于Connections 
 
Erlang processes 
erlang启动的进程实际数量和限制值。 
 
Memory 
当前broker占用的内存实际值和限制值 
 
Disk space 
当前broker占用的磁盘实际值和限制值。 
 
Uptime 
当前broker持续运行的时长。 
 
Info 
当前broker基本配置信息。 
 
Reset stats 
重启节点或者集群。 
 
 
1.3. Churn statistics(生产统计) 
1.4. Port and contexts(相关使用端口描述) 
1.5. Export definitions(导出配置) 
1.6. Import definitions(导入配置) 
2. Connections(连接) 
2.1 Overview(概览) 
参数 
简述 
 
 
Virtual host 
Vhost名称。 
 
Name 
客户端连接的IP和端口。 
 
User name 
连接使用的用户名。 
 
State 
当前的状态。running:运行中;idle:空闲。 
 
 
2.2 Detail(详情) 
参数 
简述 
 
 
SSL/TLS 
是否使用ssl进行连接。 
 
Protocol 
使用的协议。 
 
Channels 
当前连接上的channel总数。 
 
Channel max 
允许的最大channel数量。 
 
Frame max 
与客户端协商的允许最大包大小,若包太大会拆分成多次发送,默认是131072=128K。 
 
Authentication 
当前连接认证方式。 
 
 
2.3 Network(网络) 
参数 
简述 
 
 
From client 
每秒发出的数据包。 
 
To client 
每秒收到的数据包。 
 
Heartbeat 
连接心跳检测时间,默认60s,设置0表示不做心跳检测。 
 
Connected at 
连接创建时间。 
 
 
3. Channels(通道) 
3.1. Overview(概览) 
参数 
简述 
 
 
Channel 
通道名称。 
 
Virtual host 
Vhost 名称。 
 
Mode 
通道保证模式(消息确认方式)C或者T,或者都不是C(confirm):Channel will send streaming publish confirmations.(确认模式)。T(transactional):Channel is transactional.(事务模式)。 
 
State 
通道状态。idle:空闲,runing:运行。 
 
 
3.2. Details(详情) 
参数 
简述 
 
 
Unconfirmed 
未确认的消息。 
 
prefetch 
通道预取消息数量。 
 
 
3.3. Transactions 
参数 
简述 
 
 
Uncommitted msgs 
未提交的消息的数量。 
 
Uncommitted acks 
未提交ACK的消息数量。 
 
 
3.4. Message rates 
参数 
简述 
 
 
publish 
产生消息的速率。 
 
confirm 
确认消息的速率。 
 
deliver/get 
获取消息的速率。 
 
redelivered 
重新投递消息的速率。 
 
ack 
消息应答的速率。 
 
 
4. Exchanges(交换机) 
参数 
简述 
 
 
Virtual host 
Vhost 名称。 
 
Name 
交换机名称。 
 
Type 
交换机类型。direct:直连,fanout:群发,headers:headers的匹配形式,tipic:广播。 
 
Features 
交互机属性。Durability(是否持久化),Auto delete(是否自动删除),Internal(是否是内部使用)。 
 
Message rate in 
消息进入的速率【接手生产者消息】。 
 
Message rate out 
消息出去的速率【将消息发送到对应队列】。 
 
 
5. Queues and Streams(队列和流) 
5.1. Overview(概览) 
参数 
简述 
 
 
Virtual host 
Vhost 名称。 
 
Name 
交换机名称。 
 
Type 
队列的类型。 
 
classic:是 RabbitMQ 的默认队列类型,也被称为 standard。它适用于大多数情况,支持消息的基本路由和持久性。 
quorum:是 RabbitMQ 引入的一个新类型,在提高队列的可靠性。quorum 队列使用一个复制机制,确保消息在多个节点上持久化,从而增强容错能力和数据可靠性。适用于高可靠性和高可用性要求的场景。 
stream:是 RabbitMQ 的流队列类型,支持大规模的消息流处理。stream 队列适用于处理大量数据流,支持消息的顺序处理和持久化。 
Features 
队列属性。D:持久化,Lim:消息最大数量限制。 
 
Consumers 
消费者数量。 
 
Consumer utilisation 
消费者使用率。 
 
state 
队列状态。idle:空闲,runing:运行。 
 
 
5.2. Messages(消息) 
参数 
简述 
 
 
Ready 
准备好可以消费的消息数量。 
 
Unacked 
正在消费但是未返回ACK的消息数量。 
 
In Memory 
在内存中的消息数量 
 
persistent 
持久化的消息数量 
 
Total 
消息总数。Ready+Unacked。 
 
 
5.3. Messages bytes 
参数 
简述 
 
 
Ready 
准备好可以消费的消息大小。 
 
In Memory 
在内存中的消息大小 
 
persistent 
持久化的消息大小 
 
Total 
消息总大小。Ready+Unacked。 
 
 
5.4. Messages rate 
参数 
简述 
 
 
incoming 
消息进入的速率。 
 
deliver/get 
获取消息的速率 
 
redelivered 
重新投递消息的速率 
 
ack 
消息应答的速率