RabbitMQ 高级特性 Consumer Ack

RabbitMQ 高级特性 Consumer Ack

  • ack指Acknowledge,确认。 表示消费端收到消息后的确认方式。
  • 三种确认方式:
    1. acknowledge=“none”
    2. acknowledge=“manual”
    3. 根据异常情况确认:acknowledge=“auto”,(使用麻烦,不演示)
  • 自动确认是指,当消息一旦被Consumer接收到,则自动确认收到,并将相应 message 从 RabbitMQ 的消息缓存中移除。但是在实际业务处理中,很可能消息接收到,业务处理出现异常,那么该消息就会丢失。
  • 手动确认方式,则需要在业务处理成功后,调用channel.basicAck(),手动签收,如果出现异常,则调用channel.basicNack()方法,让其自动重新发送消息。

  • 消费者步骤:
    1. 创建工程
      在这里插入图片描述

    2. pom.xml导包

       <dependencies>
              <!--spring 上下文-->
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-context</artifactId>
                  <version>5.1.7.RELEASE</version>
              </dependency>
      
              <!-- spring 整合rabbit-->
              <dependency>
                  <groupId>org.springframework.amqp</groupId>
                  <artifactId>spring-rabbit</artifactId>
                  <version>2.1.8.RELEASE</version>
              </dependency>
      
              <!-- 单元测试-->
              <dependency>
                  <groupId>junit</groupId>
                  <artifactId>junit</artifactId>
                  <version>4.12</version>
              </dependency>
      
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-test</artifactId>
                  <version>5.1.7.RELEASE</version>
              </dependency>
      
          </dependencies>
      
      
          <build>
              <plugins>
                  <!-- 编译插件包-->
                  <plugin>
                      <groupId>org.apache.maven.plugins</groupId>
                      <artifactId>maven-compiler-plugin</artifactId>
                      <version>3.8.0</version>
                      <configuration>
                          <source>1.8</source>
                          <target>1.8</target>
                      </configuration>
                  </plugin>
              </plugins>
          </build>
      
      
    3. resources目录下创建rabbitmq.properties文件

      rabbitmq.host=192.168.20.146
      rabbitmq.port=5672
      rabbitmq.username=test
      rabbitmq.password=test
      rabbitmq.virtual-host=/test
      
    4. resources目录下创建spring-rabbitmq-producer.xml文件

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:context="http://www.springframework.org/schema/context"
             xmlns:rabbit="http://www.springframework.org/schema/rabbit"
             xmlns:rabbitmq="http://www.springframework.org/schema/rabbit"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans.xsd
             http://www.springframework.org/schema/context
             https://www.springframework.org/schema/context/spring-context.xsd
             http://www.springframework.org/schema/rabbit
             http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
          <!--加载配置文件-->
          <context:property-placeholder location="classpath:/rabbitmq.properties"/>
      
          <!-- 定义rabbitmq connectionFactory -->
          <rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}"
                                     port="${rabbitmq.port}"
                                     username="${rabbitmq.username}"
                                     password="${rabbitmq.password}"
                                     virtual-host="${rabbitmq.virtual-host}"
                                     publisher-confirms="true"
                                     publisher-returns="true"
          />
          <!-- 定义包扫描-->
          <context:component-scan base-package="com.yang.listener"/>
      
      </beans>
      
    5. 创建一个类实现MessageListener接口
      在这里插入图片描述

    6. spring-rabbitmq-producer.xml文件配置监听容器(ref是监听的类,queue-names是监听的队列 RabbitMQ 高级特性 - 消息的可靠性投递中的队列)
      在这里插入图片描述

      <!-- 定义监听器容器 -->
          <rabbitmq:listener-container connection-factory="connectionFactory">
              <rabbit:listener ref="ackListener" queue-names="test_queue_confirm"/>
          </rabbitmq:listener-container>
      
    7. AckListener类的内容

      package com.yang.listener;
      
      import org.springframework.amqp.core.Message;
      import org.springframework.amqp.core.MessageListener;
      import org.springframework.stereotype.Component;
      
      @Component
      public class AckListener implements MessageListener {
          @Override
          public void onMessage(Message message) {
              System.out.println(new String(message.getBody()));
          }
      }
      
      
    8. 在测试类写个死循环,看看能不能监听到

      package com.yang.test;
      
      import org.junit.Test;
      import org.junit.runner.RunWith;
      import org.springframework.amqp.rabbit.core.RabbitTemplate;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.test.context.ContextConfiguration;
      import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
      
      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration(locations = "classpath:spring-rabbitmq-consumer.xml")
      public class ConsumerTest {
      
          @Test
          public void test() {
              while(true) {
                  
              }
          }
      
      }
      
      
    9. 运行结果
      在这里插入图片描述


  • Ack手动签收(刚刚其实就是自动签收(默认))
    • 步骤:
      1. 在spring-rabbitmq-producer.xml文件定义监听容器中配置手动签收acknowledge="manual"

        <!-- 定义监听器容器 -->
            <rabbitmq:listener-container connection-factory="connectionFactory" acknowledge="manual">
                <rabbit:listener ref="ackListener" queue-names="test_queue_confirm"/>
            </rabbitmq:listener-container>
        
    1. 监听器实现ChannelAwareMessageListener

      package com.yang.listener;
      
      import com.rabbitmq.client.Channel;
      import org.springframework.amqp.core.Message;
      import org.springframework.amqp.core.MessageListener;
      import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
      import org.springframework.stereotype.Component;
      
      import java.io.IOException;
      
      /**
       * Consumer ACK机制:
       *  1. 设置手动签收.acknowledge="manual"
       *  2. 让监听器实现ChannelAwareMessageListener
       *  3. 如果消息处理成功, 则调用channel的basicAck()签收
       *  4. 如果消息处理失败, 则调用channel的basicNack()拒绝签收.broker重新发送给consumer
       */
      @Component
      public class AckListener implements ChannelAwareMessageListener {
      
          @Override
          public void onMessage(Message message, Channel channel) throws Exception {
              long deliveryTag = message.getMessageProperties().getDeliveryTag();
              try {
                  //1. 接受消息
                  System.out.println(new String(message.getBody()));
                  //2. 处理业务逻辑 打印一句话代表
                  System.out.println("处理业务逻辑");
                  //3. 手动签收
                  /*
                      basicAck(long deliveryTag, boolean multiple)参数说明:
                          deliveryTag: tag标签
                          multiple: true允许多条消息被签收
                   */
                  channel.basicAck(deliveryTag,true);
              } catch (Exception e) {
                  //4. 拒绝签收
                  /*
                  basicNack(long deliveryTag, boolean multiple, boolean requeue)参数说明:
                      deliveryTag:  tag标签
                      multiple:     true允许多条消息被签收
                      requeue:      重回队列.如果为true.则重新回到queue,broker会重新发送消息给消费端
                   */
                  channel.basicNack(deliveryTag,true,true);
              }
          }
      }
      
      
    2. 可以假装业务逻辑错误

      //2. 处理业务逻辑 打印一句话代表
      System.out.println("处理业务逻辑");
      int i = 3/0;
      

  • 小结
    • 在rabbit:listener-container标签中设置acknowledge属性,设置ack方式 none:自动确认,manual:手动确认
    • 如果在消费端没有出现异常,则调用channel.basicAck(deliveryTag,false);方法确认签收消息
    • 如果在消费端没有出现异常,则调用channel.basicAck(deliveryTag,false);方法确认签收消息

消息可靠性总结

  1. 持久化
    • exchange要持久化
    • queue要持久化
    • message要持久化
  2. 生产方确认Confirm
  3. 消费方确认Ack
  4. Broker高可用
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现RabbitMQ的手动ackacknowledge)代码,您可以按照以下步骤进行操作: 1. 首先,在RabbitMQ配置文件或者使用代码配置的方式中,设置`acknowledge="manual"`,表示使用手动确认模式。 2. 创建一个消费者类(比如MqConsumer),并实现接口ChannelAwareMessageListener,该接口中有一个方法onMessage用于接收消息。 3. 在onMessage方法中,处理接收到的消息,并在处理完成后调用channel.basicAck方法来手动确认消息的消费。 例如,可以在onMessage方法中的代码如下所示: ```java @Override public void onMessage(Message message, Channel channel) throws Exception { try { // 处理接收到的消息 // ... // 手动确认消息的消费 channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); } catch (Exception e) { // 发生异常时可以选择进行消息的拒绝或者重新投递 // ... } } ``` 4. 如果在处理消息时发生异常,您可以选择进行消息的拒绝或者重新投递,这取决于您的业务需求。 请注意,在手动确认模式下,如果消费者未调用channel.basicAck方法确认消息消费,消息将会一直保留在RabbitMQ的消息缓存中,直到消费者重新连接或者超时。因此,在实现手动ack代码时,确保正确处理消息的消费以及异常情况的处理是非常重要的。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [rabbitmq自动及手动ACK](https://blog.csdn.net/qq_18671415/article/details/115349452)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值