RabbitMQ之基础(一)

本文详细介绍了RabbitMQ的使用,包括引入依赖、配置虚拟主机、消息投递策略,以及各种交换机类型。重点讲解了消息确认机制,包括手动确认和自动确认,并提供了示例代码。此外,还讨论了消费端限流、死信队列(DLX)的情况,帮助读者理解RabbitMQ的高级特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引入RabbitMQ

依赖

<!--mq-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
    <version>2.2.2.RELEASE</version>
</dependency>

常用配置

application.yml

# rabbitmq配置
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.password=guest
spring.rabbitmq.username=guest
spring.rabbitmq.virtual-host=MyHost1	//自定义的,在RabbitMQ页面手动创建一个,不配置使用RabbitMQ默认的"/" host
##消息确认配置项(手动确认要配置)
#1.确认消息已发送到交换机(Exchange)
spring.rabbitmq.publisher-confirm-type=correlated
#2.确认消息已经发送到队列(Queue)
spring.rabbitmq.publisher-returns=true

虚拟主机

rabbitMQ默认的虚拟主机为: “/” 。可通过RabbitMQ管理界面创建自定义虚拟主机,也可以通过以下命令:

#创建虚拟主机
rabbitmqctl add vhost [vhost_name]
#删除虚拟主机
rabbitmqctl delete vhost [vhost_name]
#列出虚拟主机
rabbitmqctl list_vhosts

消息投递策略

重启RabbitMQ服务器后队列和交换机会消失(durable属性默认为false),可设置队列和交换机的durable属性为true来持久化。

常用的交换机类型

direct

消息就投递到对应路由键匹配的队列

fanout

投递消息给所有绑定在当前交换机上面的队列

topic:

*,如:topic.hello
只有是消息携带的路由键是topic.hello,才会分发到该队列。

#,如:topic.#
只要是消息携带的路由键是以topic.开头,都会分发到该队列

常用

手动确认用法,简单用法demo参考:mycourse,example1项目。

消息确认

   推送消息存在四种情况:
      ①消息推送到server,但是在server里找不到交换机
      ②消息推送到server,找到交换机了,但是没找到队列
      ③消息推送到sever,交换机和队列啥都没找到
      ④消息推送成功

消费者端

@Override
public void onMessage(Message message, Channel channel) throws Exception {
	  long deliveryTag = message.getMessageProperties().getDeliveryTag();
	  // todo:业务处理
	   
	   //业务处理结果成功
	  if (true) {  
	  // 消费确认
       //channel.basicAck(deliveryTag, false) 第二个参数,手动确认可以被批处理,当该参数为 true 时,则可以一次性确认 delivery_tag 小于等于传入值的所有消息
        // channel.basicReject(deliveryTag, true);//第二个参数,true会重新放回队列,所以需要自己根据业务逻辑判断什么时候使用拒绝
      	channel.basicAck(deliveryTag, false);
      } else {

//
//    channel.basicNack(deliveryTag, false, true);
//    第一个参数依然是当前消息到的数据的唯一id;
//    第二个参数是指是否针对多条消息;如果是true,也就是说一次性针对当前通道的消息的tagID小于当前这条消息的,都拒绝确认。
//    第三个参数是指是否重新入列,也就是指不确认的消息是否重新丢回到队列里面去。
     	 channel.basicNack(deliveryTag, false, false);
      }
}
自动确认

自动确认, 这也是默认的消息确认情况。 AcknowledgeMode.NONE

根据情况确认

AcknowledgeMode.AUTO:

手动确认

开启AcknowledgeMode.MANUAL。
container.setAcknowledgeMode(AcknowledgeMode.MANUAL); // RabbitMQ默认是自动确认,这里改为手动确认消息

basic.ack用于肯定确认
basic.nack用于否定确认(这是AMQP 0-9-1的RabbitMQ扩展)
basic.reject用于否定确认,但与basic.nack相比有一个限制:一次只能拒绝单条消息

消费者端以上的3个方法都表示消息已经被正确投递,但是basic.ack表示消息已经被正确处理。而basic.nack,basic.reject表示没有被正确处理

1. channel.basicReject(deliveryTag, true);  
	拒绝消费当前消息,如果第二参数传入true,就是将数据重新丢回队列里,那么下次还会消费这消息。设置false,就是告诉服务器,我已经知道这条
消息数据了,因为一些原因拒绝它,而且服务器也把这个消息丢掉就行。 下次不想再消费这条消息了。
    使用拒绝后重新入列这个确认模式要谨慎,因为一般都是出现异常的时候,catch异常再拒绝入列,选择是否重入列,如果使用不当会导致一些每次都
被你重入列的消息一直消费-入列-消费-入列这样循环,会导致消息积压。

2.channel.basicNack(deliveryTag, false, true);
	第一个参数依然是当前消息到的数据的唯一id;
	第二个参数是指是否针对多条消息;如果是true,也就是说一次性针对当前通道的消息的tagID小于当前这条消息的,都拒绝确认。
	第三个参数是指是否重新入列,也就是指不确认的消息是否重新丢回到队列里面去。

生成者端

rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
	  	@Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                if (ack) {
                    //如果confirm返回成功 则进行更新消息投递成功
                    String msgId = correlationData.getId();
                   // 更新msgId对应状态为deliver_success
                } else {
                    //失败则进行具体的后续操作:重试 等
                    LOG.warn("<--消息发送到Exchange失败-->" + correlationData + cause);
                }
            }
})

交换机或路由键不存在

指定的路由键不存在,或者交换机不存在,那么消息就会return。

rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
     @Override
     public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {

	   LOG.warn("<---消息从Exchange路由到Queue失败--->");
       LOG.warn("ReturnCallback:     "+"消息:"+message);
       LOG.warn("ReturnCallback:     "+"回应码:"+replyCode);
       LOG.warn("ReturnCallback:     "+"回应信息:"+replyText);
       LOG.warn("ReturnCallback:     "+"交换机:"+exchange);
       LOG.warn("ReturnCallback:     "+"路由键:"+routingKey);
    }
});

消费端限流

Qos在非自动确认消息的情况下,在一定数量的消息未被消费前,不进行消费新的消息。

// prefetchSize消息的限制大小,一般设置为0,在生产端限制
// prefetchCount 我们一次最多消费多少条消息,一般设置为1
// global,一般设置为false,在消费端进行限制
channel.basicQos(int prefetchSize, int prefetchCount, boolean global) 

// 使用
channel.basicQos(0, 1, false);
channel.basicConsume(queueName, false, new MyConsumer(channel));    

死信队列(DLX)

进入死信队列3种情况:

1、basic.reject/basic.nack 并且 requeue为false(不重回队列)
2、消息TTL过期
3、队列达到最大的长度
RabbitMQ个开源的消息中间件,主要用于实现系统间的异步通信和解耦。其核心概念包括生产者(Producer)、消费者(Consumer)、队列(Queue)、交换机(Exchange)和绑定(Binding)。生产者将消息发送到交换机,交换机根据绑定规则将消息路由到个或多个队列中,消费者从队列中获取并处理消息 [^3]。 ### 核心组件与工作流程 - **生产者(Producer)**:负责生成消息并将其发送到交换机。 - **交换机(Exchange)**:接收来自生产者的消息,并根据绑定规则决定将消息发送到哪些队列。RabbitMQ 支持多种类型的交换机,如直连(Direct)、扇出(Fanout)、主题(Topic)和头部(Headers)交换机 [^2]。 - **队列(Queue)**:存储消息的缓冲区,直到消费者处理它们。 - **消费者(Consumer)**:从队列中获取消息并进行处理。 - **绑定(Binding)**:定义了交换机与队列之间的关系,通常通过路由键(Routing Key)来指定消息的路由规则 [^3]。 ### 消息确认机制 为了确保消息不会因为消费者崩溃而丢失,RabbitMQ 提供了手动确认(ACK)机制。消费者在处理完消息后,必须显式地向 RabbitMQ 发送确认信号,告知该消息已经成功处理。如果消费者在处理消息时发生错误或崩溃,RabbitMQ 将不会收到确认信号,并会将消息重新放入队列中,以便其他消费者可以处理它 [^1]。 ### 流量控制与公平分发 当多个消费者同时从同个队列中消费消息时,可能会出现某些消费者负载过高的情况。为了解决这个问题,RabbitMQ 提供了 `basicQos` 方法,允许设置 `prefetchCount` 参数。通过将 `prefetchCount` 设置为 1,可以确保 RabbitMQ 不会在消费者尚未确认前条消息之前向其发送新的消息。这样可以实现更公平的消息分发,避免某些消费者过载 [^1]。 ### 主题交换机(Topic Exchange) 主题交换机是种灵活的路由方式,它使用通配符来匹配路由键。`*` 可以匹配个单词,而 `#` 可以匹配零个或多个单词。这种方式非常适合需要根据多个条件进行路由的场景 [^2]。 ### 示例代码:使用 Python 和 `pika` 库发送和接收消息 ```python import pika # 连接到 RabbitMQ 服务器 connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() # 声明个名为 'hello' 的队列 channel.queue_declare(queue='hello') # 发送消息到 'hello' 队列 channel.basic_publish(exchange='', routing_key='hello', body='Hello World!') print(" [x] Sent 'Hello World!'") # 关闭连接 connection.close() ``` ```python import pika # 连接到 RabbitMQ 服务器 connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() # 声明个名为 'hello' 的队列 channel.queue_declare(queue='hello') # 定义回调函数,用于处理接收到的消息 def callback(ch, method, properties, body): print(f" [x] Received {body}") # 手动确认消息 ch.basic_ack(delivery_tag=method.delivery_tag) # 开始消费消息 channel.basic_consume(queue='hello', on_message_callback=callback) print(' [*] Waiting for messages. To exit press CTRL+C') # 启动消费者循环 channel.start_consuming() ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值