简介
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
消息应答的速率