【消息队列】MQ进阶篇之 RocketMQ 的实践

本文详细介绍了如何在Java项目中使用ApacheRocketMQ进行消息的同步、异步和单向发送,包括生产者配置、消息创建和发送过程,以及消费者实例的创建、消息监听和主题订阅。同时讨论了消费者实践中的注意事项,如消费者组、并发消费、消息重试和过滤等。
摘要由CSDN通过智能技术生成

建议先看【消息队列】MQ进阶篇之 RocketMQ 的理论,非常通俗易懂。不懂你来找我!

一、客户端配置

添加客户端依赖在 pom.xml 中

<dependency>
  <groupId>org.apache.rocketmq</groupId>
  <artifactId>rocketmq-client</artifactId>
  <version>4.9.4</version>
</dependency>

二、生产者发送

Apache RocketMQ可用于以三种方式发送消息:同步、异步和单向传输。前两种消息类型是可靠的,因为无论它们是否成功发送都有响应。
下面是三种方式的解析图解。
在这里插入图片描述
在这里插入图片描述

1、举例详细介绍一下同步消息发送:

  1. 首先会创建一个producer。普通消息可以创建 DefaultMQProducer,创建时需要填写生产组的名称,生产者组是指同一类Producer的集合,这类Producer发送同一类消息且发送逻辑一致。
  2. 设置 NameServer 的地址。Apache RocketMQ很多方式设置NameServer地址(客户端配置中有介绍),这里是在代码中调用producer的API setNamesrvAddr进行设置,如果有多个NameServer,中间以分号隔开,比如"127.0.0.2:9876;127.0.0.3:9876"。
  3. 第三步是构建消息。指定topic、tag、body等信息,tag可以理解成标签,对消息进行再归类,RocketMQ可以在消费端对tag进行过滤。
  4. 最后调用send接口将消息发送出去。同步发送等待结果最后返回SendResult,SendResut包含实际发送状态还包括SEND_OK(发送成功),FLUSH_DISK_TIMEOUT(刷盘超时), FLUSH_SLAVE_TIMEOUT(同步到备超时),SLAVE_NOT_AVAILABLE(备不可用),如果发送失败会抛出异常。
public class SyncProducer {
  public static void main(String[] args) throws Exception {
    // 初始化一个producer并设置Producer group name
    DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name"); //(1)
    // 设置NameServer地址
    producer.setNamesrvAddr("localhost:9876");  //(2)
    // 启动producer
    producer.start();
    for (int i = 0; i < 100; i++) {
      // 创建一条消息,并指定topic、tag、body等信息,tag可以理解成标签,对消息进行再归类,RocketMQ可以在消费端对tag进行过滤
      Message msg = new Message("TopicTest" /* Topic */,
        "TagA" /* Tag */,
        ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */
        );   //(3)
      // 利用producer进行发送,并同步等待发送结果
      SendResult sendResult = producer.send(msg);   //(4)
      System.out.printf("%s%n", sendResult);
    }
    // 一旦producer不再使用,关闭producer
    producer.shutdown();
  }
}

在使用 RocketMQ 发送消息的项目中,通常的做法是在项目启动时初始化 RocketMQ 的生产者(Producer),并在需要发送消息时使用该生产者发送消息。这样可以保证在整个项目运行期间都有可用的生产者实例,并避免在每次发送消息时都初始化生产者,提高效率。

具体的步骤包括:

  1. 初始化生产者: 在项目启动时,初始化 RocketMQ 生产者。这通常涉及设置生产者的配置,如 NameServer 地址、生产者组名等。初始化生产者的时候,可以选填一些其他参数,举例说明,第二个参数类型Boolean ,表示是否开启消息轨迹。

    DefaultMQProducer producer = new DefaultMQProducer("ProducerGroup",true);
    producer.setNamesrvAddr("localhost:9876");
    producer.start();
    
  2. 发送消息: 在需要发送消息的地方,使用初始化好的生产者发送消息。

    Message message = new Message("TopicTest", "TagA", "HelloRocketMQ".getBytes(StandardCharsets.UTF_8)); 
    SendResult sendResult = producer.send(message);
    
  3. 关闭生产者: 在项目关闭或其他适当的时机,关闭 RocketMQ 生产者。

     java Copy code producer.shutdown();
    

通过这样的方式,生产者在项目启动时初始化,一直处于可用状态,而不需要每次发送消息都重新初始化。这有助于提高性能和效率。spring项目中自启动参考【注解】@Bean(initMethod = “start“, destroyMethod= “shutdown“)

请注意,生产者的初始化是一个相对耗时的操作,因此最好在项目启动时进行。另外,RocketMQ 的生产者是线程安全的,可以在整个应用程序的生命周期内重复使用。

2、异步消息发送

异步发送是指发送方发出一条消息后,不等服务端返回响应,接着发送下一条消息的通讯方式。

消息发送方在发送了一条消息后,不需要等待服务端响应即可发送第二条消息,发送方通过回调接口接收服务端响应,并处理响应结果。异步发送一般用于链路耗时较长,对响应时间较为敏感的业务场景。例如,视频上传后通知启动转码服务,转码完成后通知推送转码结果等。

异步发送与同步发送代码唯一区别在于调用send接口的参数不同,异步发送不会等待发送返回,取而代之的是send方法需要传入 SendCallback 的实现,SendCallback 接口主要有onSuccessonException 两个方法,表示消息发送成功和消息发送失败。此处和前端的promise有异曲同工之处,对前端有兴趣的同学可以参考谈谈前端开发中的同步和异步,promise、async/await,应用场景,以及在事件循环机制中的区别
示例代码,来自官方文档。

public class AsyncProducer {
  public static void main(String[] args) throws Exception {
    // 初始化一个producer并设置Producer group name
    DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
    // 设置NameServer地址
    producer.setNamesrvAddr("localhost:9876");
    // 启动producer
    producer.start();
    producer.setRetryTimesWhenSendAsyncFailed(0);
    int messageCount = 100;
    final CountDownLatch countDownLatch = new CountDownLatch(messageCount);
    for (int i = 0; i < messageCount; i++) {
      try {
          final int index = i;
          // 创建一条消息,并指定topic、tag、body等信息,tag可以理解成标签,对消息进行再归类,RocketMQ可以在消费端对tag进行过滤
          Message msg = new Message("TopicTest",
            "TagA",
            "Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET));
          // 异步发送消息, 发送结果通过callback返回给客户端
          producer.send(msg, new SendCallback() {
            @Override
            public void onSuccess(SendResult sendResult) {
              System.out.printf("%-10d OK %s %n", index,
                sendResult.getMsgId());
              countDownLatch.countDown();
            }
            @Override
            public void onException(Throwable e) {
              System.out.printf("%-10d Exception %s %n", index, e);
              e.printStackTrace();
              countDownLatch.countDown();
            }
          });
        } catch (Exception e) {
            e.printStackTrace();
            countDownLatch.countDown();
        }
    }
    //异步发送,如果要求可靠传输,必须要等回调接口返回明确结果后才能结束逻辑,否则立即关闭Producer可能导致部分消息尚未传输成功
    countDownLatch.await(5, TimeUnit.SECONDS);
    // 一旦producer不再使用,关闭producer
    producer.shutdown();
  }
}

3、单向发送

发送方只负责发送消息,不等待服务端返回响应且没有回调函数触发,即只发送请求不等待应答。此方式发送消息的过程耗时非常短,一般在微秒级别。适用于某些耗时非常短,但对可靠性要求并不高的场景,例如日志收集。

单向模式调用方法 sendOneway,不会对返回结果有任何等待和处理。其他和同步异步发送消息逻辑一致。

三、消费者实践

有pull 和 push 两种消费者,介绍参考【消息队列】MQ进阶篇之 RocketMQ 的理论。此处以 push 消费者在项目中的实践举例说明。

1、创建消费者实例:

使用 DefaultMQPushConsumer 类创建一个消费者实例,并设置消费者组、NameServer 地址等参数。

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;

DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("YourConsumerGroup");
consumer.setNamesrvAddr("localhost:9876");

2、注册消息监听器:

注册消息监听器,实现消息的消费逻辑。在监听器中处理业务逻辑,并返回消费状态。

import org.apache.rocketmq.client.consumer.listener.*;
import org.apache.rocketmq.common.message.MessageExt;

consumer.registerMessageListener(new MessageListenerConcurrently() {
    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
        for (MessageExt msg : msgs) {
            // 处理消息的业务逻辑...
            System.out.println("Received message: " + new String(msg.getBody()));
        }
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
});

3、订阅主题和标签:

使用 subscribe 方法订阅消息主题和标签。

consumer.subscribe("YourTopic", "YourTag");

4、启动消费者:

启动消费者实例,开始接收和消费消息。此处也同生产者在spring中的应用,可参考 spring项目中自启动参考【注解】@Bean(initMethod = “start“, destroyMethod= “shutdown“)

consumer.start();

5、关闭消费者:

在程序结束时,需要关闭消费者实例。

consumer.shutdown();

注意事项:

  • 消费者组(Consumer Group): 每个消费者都应该属于一个消费者组,同一个消费者组内的消费者将共同消费相同的消息,实现负载均衡和容错。
  • 并发消费: 在实际应用中,可以考虑使用多线程来实现并发消费,提高消息处理的效率。需要注意线程安全和业务逻辑的一致性。
  • 消息重试: 如果消息处理失败,RocketMQ 会进行消息重试。因此,消费者的业务逻辑应该是幂等的,即多次执行不会产生不同的结果。
  • 异常处理: 在消息监听器中处理异常,可以记录日志、进行重试等操作,确保消息不会因为消费失败而丢失。
  • 定时消息: 如果涉及到定时消息,注意处理定时消息的特殊逻辑。
  • 消息过滤: 在订阅消息时,可以通过设置标签(Tag)来进行消息过滤,只消费感兴趣的消息。

以上是一个简单的 RocketMQ 消费者的实践流程。根据实际业务需求,可能需要考虑更多的细节和调优。在设计消费者时,根据业务场景和需求选择合适的消费模式、并发处理方式和异常处理策略。

持续更新ing , 动动小手,点点关注,后续更精彩!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值