RocketMQ 安装使用

一、RocketMQ 初相识

在分布式系统的广袤天地中,RocketMQ 宛如一颗璀璨的明星,作为一款高性能的分布式消息队列,它肩负着至关重要的使命。其核心价值在于为分布式系统提供了强大的解耦能力,犹如在复杂的系统架构中搭建了一座座桥梁,让各个组件能够独立运作,互不干扰。同时,在面对流量高峰时,RocketMQ 展现出卓越的削峰填谷能力,能够平稳地处理大量突发请求,确保系统的稳定性与可靠性。

想象一下,在电商系统中,当一场盛大的促销活动开启,瞬间涌入的海量订单信息如同汹涌的潮水。此时,RocketMQ 便挺身而出,它将这些订单消息迅速收集并存储起来,然后按照系统能够承受的速度,逐步将消息传递给后续的处理模块。这样一来,不仅避免了因瞬间高流量导致系统崩溃的风险,还使得各个业务模块能够专注于自身的核心任务,极大地提高了系统的整体性能和可扩展性。 正是凭借这些出色的特性,RocketMQ 在分布式系统领域中占据了不可或缺的地位,成为众多开发者构建高性能、高可靠性系统的首选工具。

二、RocketMQ 的安装之旅

(一)安装前奏曲

在开启 RocketMQ 的安装征程之前,我们首先要确保系统环境满足一系列要求。就如同建造高楼大厦需要坚实的地基一样,RocketMQ 的稳定运行依赖于合适的基础环境。

RocketMQ 对 Java Development Kit(JDK)有着明确的要求,必须为 64 位的 JDK 1.8 及以上版本 。这是因为 RocketMQ 作为一款基于 Java 开发的消息队列,其底层的运行逻辑和性能优化都与 JDK 的版本和特性紧密相关。若 JDK 版本过低,可能无法支持 RocketMQ 的某些高级功能,甚至导致安装和运行过程中出现各种兼容性问题。

操作系统方面,RocketMQ 支持多种常见的 64 位系统,如 Linux、Unix、Mac 以及 Windows 。不同的操作系统在系统架构、文件管理、进程调度等方面存在差异,但 RocketMQ 都进行了针对性的适配,以确保在各种环境下都能稳定运行。不过,在实际选择操作系统时,需要综合考虑项目的整体架构、服务器资源以及运维团队的熟悉程度等因素。例如,在大型企业级项目中,Linux 系统因其稳定性、高效性以及丰富的开源工具生态,往往成为首选;而在开发测试环境中,Windows 系统则因其操作的便捷性,受到开发者的青睐。

(二)下载与解压

当我们的系统环境准备就绪后,便可以着手下载 RocketMQ 的安装包了。RocketMQ 的官方网站(rocketmq.apache.org/download/ )是获取安装包的权威来源,在这里,我们能够找到最新版本的 RocketMQ。

在下载页面,我们会看到 RocketMQ 提供了两种类型的安装包,一种是源代码版本,另一种是已经编译好的二进制版本。对于大多数开发者来说,二进制版本更为便捷,它免去了繁琐的编译过程,能够快速投入使用。而源代码版本则适合那些对 RocketMQ 内部机制有深入研究需求,或者需要根据特定场景对 RocketMQ 进行定制化开发的用户。

假设我们选择下载二进制版本,下载完成后,得到的是一个压缩文件,如 rocketmq-all-5.1.0-bin-release.zip 。接下来,我们需要将这个压缩文件解压到指定的目录。解压操作十分简单,在 Linux 系统中,我们可以使用命令 unzip rocketmq-all-5.1.0-bin-release.zip -d /opt/rocketmq,将其解压到 /opt/rocketmq 目录下;在 Windows 系统中,我们可以通过解压工具,如 WinRAR 或 7-Zip,选择解压路径进行解压。解压完成后,我们便可以在指定目录下看到 RocketMQ 的文件结构,其中包含了 bin、conf、lib 等重要目录,这些目录分别存放着启动脚本、配置文件以及依赖的库文件等,它们共同构成了 RocketMQ 运行的基础。

(三)配置文件大改造

解压完成后,进入 RocketMQ 的安装目录,我们会发现一个至关重要的 conf 目录,这里存放着 RocketMQ 的各种配置文件。为了让 RocketMQ 能够更好地适应我们的系统环境和业务需求,对这些配置文件进行适当的修改是必不可少的步骤。

在这些配置文件中,启动配置文件尤为关键。以 Linux 系统为例,在 bin 目录下的 runserver.shrunbroker.sh 文件分别用于启动 NameServer 和 Broker。打开 runserver.sh 文件,我们可以看到其中的 JAVA_OPT 配置项,它用于设置 Java 虚拟机的启动参数。默认情况下,RocketMQ 可能会根据自身的推荐配置设置一些参数,但在实际应用中,我们往往需要根据服务器的内存情况进行调整。比如,如果服务器的内存资源有限,我们可以将 JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn125m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m 中的初始堆内存(-Xms)和最大堆内存(-Xmx)适当减小,以避免因内存分配过大导致系统资源不足。同理,对于 runbroker.sh 文件,也需要进行类似的内存参数调整,确保 Broker 在启动时能够合理地使用内存资源 。

除了内存参数,我们还可能需要根据实际的网络环境和集群部署要求,对配置文件中的其他参数进行修改。例如,如果我们的 RocketMQ 集群需要与外部的其他系统进行通信,那么就需要在配置文件中指定正确的网络地址和端口号,以确保消息能够准确无误地传输。

(四)启动 RocketMQ

当我们完成了配置文件的修改后,就可以正式启动 RocketMQ 了。RocketMQ 的启动过程分为两个主要步骤,分别是启动 NameServer 和启动 Broker。

在启动 NameServer 时,我们进入 RocketMQ 的 bin 目录,执行命令 sh mqnamesrv 。此时,NameServer 便开始启动,为整个 RocketMQ 集群提供命名服务。NameServer 就像是一个庞大的通讯录,记录着各个 Broker 的地址和相关信息,为生产者和消费者在发送和接收消息时提供路由指引。启动成功后,我们可以通过日志来确认,如果能够看到类似 The Name Server boot success 的日志信息,那就说明 NameServer 已经成功启动。

接下来,启动 Broker。在启动 Broker 之前,我们需要确保 NameServer 已经正常运行。同样进入 bin 目录,执行命令 sh mqbroker -n localhost:9876 。这里的 -n localhost:9876 参数指定了 NameServer 的地址和端口。Broker 启动后,会连接到指定的 NameServer,并将自身的信息注册到 NameServer 中。我们可以通过查看日志来确认 Broker 是否启动成功,如果在日志中看到 The broker XXXX boot success. serializeType=JSON and name server is XXXX 的信息,XXXX表示你的服务信息,就表明 Broker 已经顺利启动。

当 NameServer 和 Broker 都成功启动后,我们还可以通过一些方式来验证 RocketMQ 是否正常工作。例如,我们可以使用 RocketMQ 自带的命令行工具,如在 bin 目录下执行 sh mqadmin updateTopic -n localhost:9876 -t testTopic -c DefaultCluster -r 8 -w 8 创建一个主题,

然后使用 sh mqadmin topicList -n localhost:9876 命令,查看当前 RocketMQ 集群中已有的主题列表。 如果能够正常列出主题信息,那就说明 RocketMQ 已经可以正常接收和处理消息,至此,我们的 RocketMQ 安装和启动工作就圆满完成了。

三、RocketMQ 消息类型全解析

在 RocketMQ 的消息宇宙中,不同类型的消息犹如各具特色的工具,为我们解决各种复杂的业务问题提供了有力支持。接下来,让我们深入了解 RocketMQ 的几种常见消息类型。 需要提前引入 pom 文件

pom 复制代码
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-client</artifactId>
    <version>5.3.1</version>
</dependency>

(一)普通消息:基础且常用

普通消息,作为 RocketMQ 中最基础的消息类型,如同建筑中的基石,承载着众多系统的基本通信需求。它的特点在于简单直接,生产者只管将消息发送至 Broker,消费者则从 Broker 拉取消息进行处理,消息之间并无特定的顺序要求。这种特性使得普通消息在许多场景中都能大显身手,尤其是在那些对消息处理顺序没有严格要求,只注重消息可靠传输的场景中。

在微服务架构中,各个微服务之间往往需要进行大量的数据交互。以一个电商系统为例,订单服务在接收到用户的下单请求后,需要将订单信息传递给库存服务、支付服务等多个下游服务。此时,使用普通消息进行解耦是非常合适的选择。订单服务将订单信息封装成普通消息发送到 RocketMQ,下游的库存服务和支付服务可以根据自身的处理能力,从 RocketMQ 中拉取消息进行处理。这样一来,即使某个下游服务出现短暂的故障或性能问题,也不会影响到订单服务的正常运行,从而实现了各个微服务之间的异步解耦,提高了系统的整体稳定性和可扩展性 。

在离线的日志收集场景中,普通消息也发挥着重要作用。通过在前端应用中埋点收集用户的操作日志,然后将这些日志数据封装成普通消息发送到 RocketMQ。RocketMQ 负责将这些消息可靠地投递到下游的存储系统和分析系统,后续的日志存储和分析工作由相应的后端应用完成。由于日志数据的处理通常不要求严格的顺序,普通消息能够高效地完成日志数据的传输任务,为系统的运维和数据分析提供了有力支持。

首先创建一个普通消息topic

shell 复制代码
sh mqadmin updateTopic -n localhost:9876 -t GeneralTopic -c DefaultCluster -r 8 -w 8
  • sh mqadmin updateTopic:使用 mqadmin 工具的 updateTopic 子命令,用于更新或创建 Topic。
  • -n localhost:9876:指定 NameServer 的地址和端口,这里使用 localhost:9876,你可以根据实际情况修改为你的 NameServer 的地址。
  • -t GeneralTopic:指定要创建的 Topic 名称,这里是 GeneralTopic,可根据需求修改。
  • -c DefaultCluster:指定集群名称,DefaultCluster 是一个示例,可以替换为实际使用的集群名称。
  • -r 8:设置读队列的数量为 8,你可以根据实际情况调整此参数。
  • -w 8:设置写队列的数量为 8,同样可根据实际情况调整。

下面,我们通过一段 Java 代码示例来看看普通消息的发送和接收过程:

java 复制代码
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;

public class Producer {

    public static void main(String[] args) throws MQClientException, MQBrokerException, RemotingException, InterruptedException {
        // 创建一个生产者实例,指定生产者组名
        DefaultMQProducer producer = new DefaultMQProducer("GeneralTopicProducerGroup");
        // 设置NameServer的地址
        producer.setNamesrvAddr("localhost:9876");
        // 启动生产者
        producer.start();
        // 创建一条消息,指定主题、标签和消息体
        Message message = new Message("GeneralTopic", "*", "Hello, RocketMQ!".getBytes());
        // 发送消息并获取发送结果
        SendResult sendResult = producer.send(message);
        System.out.println(sendResult);
        // 关闭生产者
        producer.shutdown();
    }

}
java 复制代码
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;

public class Consumer {
    public static void main(String[] args) throws MQClientException {
        // 创建一个消费者实例,指定消费者组名
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("GeneralTopicConsumerGroup");
        // 设置NameServer的地址
        consumer.setNamesrvAddr("localhost:9876");
        // 订阅主题
        consumer.subscribe("GeneralTopic", "*");
        // 注册消息监听器,处理接收到的消息
        consumer.registerMessageListener((MessageListenerConcurrently) (messageList, context) -> {
            for (MessageExt msg : messageList) {
                System.out.println(new String(msg.getBody()));
            }
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        });
        // 启动消费者
        consumer.start();
    }
}

(二)顺序消息:有序的保障

在某些业务场景中,消息的顺序性至关重要。例如在订单处理系统中,订单的创建、支付、发货等操作必须严格按照顺序进行,否则可能会导致业务逻辑混乱。这时,顺序消息便成为了我们的得力助手。

顺序消息的核心原理在于,通过将具有相同 "分区键"(通常是业务相关的唯一标识符,如订单 ID)的消息发送到同一个队列中,而队列本身是按照先进先出(FIFO)的顺序进行存储和投递的,从而确保了消费者能够按照消息的发送顺序进行消费。在一个电商订单处理系统中,对于同一订单的所有相关消息,如订单创建消息、支付成功消息、发货消息等,都可以使用该订单的 ID 作为分区键。这样,这些消息都会被发送到同一个队列中,消费者从该队列中拉取消息时,就能够保证按照订单处理的正确顺序依次处理这些消息,避免了因消息乱序而导致的业务错误 。

在金融交易系统中,股票买卖、资金划转等操作也需要严格按照顺序执行。以股票交易为例,先买入股票再卖出股票的顺序是不能颠倒的。通过使用顺序消息,将同一股票账户的所有交易消息发送到同一个队列,消费者按照顺序处理这些消息,就能确保交易的一致性和准确性,有效避免了因消息顺序错误而引发的交易风险。

首先创建一个顺序消息topic

shell 复制代码
sh mqadmin updateTopic -n localhost:9876 -t OrderTopic -c DefaultCluster -r 8 -w 8 -o true
  • sh mqadmin updateTopic:使用 mqadmin 工具的 updateTopic 子命令。
  • -n localhost:9876:指定 NameServer 的地址和端口,这里是 localhost:9876
  • -t OrderTopic:指定要创建的 Topic 名称,这里是 OrderTopic
  • -c DefaultCluster:指定集群名称,这里是 DefaultCluster,你可以根据实际情况修改为你所使用的集群名称。
  • -r 8:设置读队列的数量为 8。
  • -w 8:设置写队列的数量为 8。
  • -o true:将 order 参数设置为 true,表示该 Topic 是一个支持顺序消息的 Topic。

下面是一个使用 Java 代码实现顺序消息发送和接收的示例:

java 复制代码
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.remoting.exception.RemotingException;

import java.util.List;

public class Producer {
    public static void main(String[] args) throws MQClientException, MQBrokerException, RemotingException, InterruptedException {
        // 创建一个生产者实例,指定生产者组名
        DefaultMQProducer producer = new DefaultMQProducer("OrderTopicProducerGroup");
        // 设置NameServer的地址
        producer.setNamesrvAddr("localhost:9876");
        // 启动生产者
        producer.start();
        // 订单ID
        String orderId = "123456";
        // 创建一条消息,指定主题、标签和消息体
        Message message = new Message("OrderTopic", "CreateOrder", ("创建订单:" + orderId).getBytes());
        // 发送消息,使用MessageQueueSelector确保消息发送到同一队列
        SendResult sendResult = producer.send(message, new MessageQueueSelector() {
            @Override
            public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
                String id = (String) arg;
                // 这里简单地根据订单ID取模选择队列,确保同一订单的消息在同一队列
                int index = Math.abs(id.hashCode()) % mqs.size();
                return mqs.get(index);
            }
        }, orderId);
        System.out.println(sendResult);
        // 关闭生产者
        producer.shutdown();
    }
}
java 复制代码
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;

public class Consumer {
    public static void main(String[] args) throws MQClientException {
        // 创建一个消费者实例,指定消费者组名
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("OrderTopicConsumerGroup");
        // 设置NameServer的地址
        consumer.setNamesrvAddr("localhost:9876");
        // 订阅主题
        consumer.subscribe("OrderTopic", "*");
        // 注册顺序消息监听器
        consumer.registerMessageListener((MessageListenerOrderly) (messageList, context) -> {
            for (MessageExt msg : messageList) {
                System.out.println(new String(msg.getBody()));
            }
            return ConsumeOrderlyStatus.SUCCESS;
        });
        // 启动消费者
        consumer.start();
    }
}

(三)定时 / 延时消息:精准的定时任务

在实际业务中,我们常常会遇到需要定时执行某些任务的场景,比如定时发送邮件通知、定时清理过期数据等。RocketMQ 的定时 / 延时消息就为我们提供了一种便捷的解决方案。

定时 / 延时消息允许我们在发送消息时指定一个延迟时间或定时时间,消息在到达指定时间后才会被消费者消费。这种特性使得它在任务调度、定时提醒等场景中有着广泛的应用。在电商系统中,对于用户下单后一段时间未支付的订单,我们可以发送一条定时消息,在订单创建后的 30 分钟触发。当消费者接收到这条消息时,检查订单状态,如果仍未支付,则自动取消订单,将商品放回库存。这样既保证了订单的时效性,又减轻了系统的实时处理压力 。

在一些需要定时进行数据备份或系统维护的场景中,定时 / 延时消息也能发挥重要作用。例如,我们可以在每天凌晨 2 点发送一条定时消息,触发数据备份任务,确保数据的安全性和完整性。通过合理设置定时 / 延时消息,我们能够实现系统的自动化运维,提高系统的稳定性和可靠性。

首先创建一个延时消息topic

shell 复制代码
sh mqadmin updateTopic -n localhost:9876 -t DelayTopic -c DefaultCluster -r 8 -w 8
  • sh mqadmin updateTopic:使用 mqadmin 工具的 updateTopic 子命令。
  • -n localhost:9876:指定 NameServer 的地址和端口,这里是 localhost:9876,可根据实际情况修改。
  • -t DelayTopic:指定要创建的 Topic 名称,这里使用 DelayTopic 作为示例,可根据需要进行替换。
  • -c DefaultCluster:指定集群名称,这里使用 DefaultCluster,根据实际使用的集群修改。
  • -r 8:设置读队列的数量为 8,可以根据实际的业务情况进行调整。
  • -w 8:设置写队列的数量为 8,同样可根据业务需求调整。

下面是一个使用 Java 代码发送定时 / 延时消息的示例:

java 复制代码
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;

public class Producer {
    public static void main(String[] args) throws MQClientException, MQBrokerException, RemotingException, InterruptedException {
        // 创建一个生产者实例,指定生产者组名
        DefaultMQProducer producer = new DefaultMQProducer("DelayTopicProducerGroup");
        // 设置NameServer的地址
        producer.setNamesrvAddr("localhost:9876");
        // 启动生产者
        producer.start();
        // 创建一条消息,指定主题、标签和消息体
        Message message = new Message("DelayTopic", "*", "定时任务消息".getBytes());
        // 设置延时等级,这里假设延时等级1表示10秒后投递(具体延时时间根据RocketMQ配置)
        // messageDelayLevel=1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
        int delayLevel = 1;
        // 发送延时消息
        SendResult sendResult = producer.send(message, delayLevel);
        System.out.println(sendResult);
        // 关闭生产者
        producer.shutdown();
    }
}
java 复制代码
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;

public class Consumer {
    public static void main(String[] args) throws MQClientException {
        // 创建一个消费者实例,指定消费者组名
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("DelayTopicConsumerGroup");
        // 设置NameServer的地址
        consumer.setNamesrvAddr("localhost:9876");
        // 订阅主题
        consumer.subscribe("DelayTopic", "*");
        // 注册顺序消息监听器
        consumer.registerMessageListener((MessageListenerOrderly) (messageList, context) -> {
            for (MessageExt msg : messageList) {
                System.out.println(new String(msg.getBody()));
            }
            return ConsumeOrderlyStatus.SUCCESS;
        });
        // 启动消费者
        consumer.start();
    }
}

在 RocketMQ 中,消费定时 / 延时消息的代码与消费普通消息的代码基本相同,消费者不需要特殊处理即可接收并处理到达时间的定时 / 延时消息。

(四)事务消息:分布式事务的利器

在分布式系统中,保证事务的一致性是一个极具挑战性的问题。RocketMQ 的事务消息为我们提供了一种有效的解决方案,它能够确保本地事务与消息发送的最终一致性。

事务消息的工作原理基于两阶段提交(2PC)和事后补偿机制。具体来说,生产者首先发送一条半事务消息(即消息已经发送到 Broker,但标记为暂不能投递),然后执行本地事务。如果本地事务执行成功,生产者向 Broker 提交事务确认,Broker 将半事务消息标记为可投递,消费者可以消费该消息;如果本地事务执行失败,生产者向 Broker 回滚事务,Broker 丢弃该半事务消息。如果 Broker 在一定时间内未收到生产者的事务确认,它会主动回查生产者的本地事务状态,生产者根据实际情况进行提交或回滚操作,从而保证了事务的最终一致性。

在电商下单场景中,当用户下单时,系统需要同时完成创建订单和扣减库存这两个操作。我们可以使用事务消息来确保这两个操作要么都成功,要么都失败。生产者首先发送一条事务消息,包含订单信息和库存扣减信息。然后执行本地事务,创建订单并尝试扣减库存。如果库存扣减成功,生产者向 Broker 提交事务确认,消费者可以接收到消息并进行后续处理,如发送订单确认邮件给用户;如果库存扣减失败,生产者回滚事务,Broker 丢弃消息,避免了因库存不足但订单已创建而导致的业务不一致问题 。

首先创建一个事物消息topic

shell 复制代码
sh mqadmin updateTopic -n localhost:9876 -t TransactionTopic -c DefaultCluster -r 8 -w 8
  • sh mqadmin updateTopic:使用 mqadmin 工具的 updateTopic 子命令。
  • -n localhost:9876:指定 NameServer 的地址和端口,这里是 localhost:9876,可根据实际情况修改。
  • -t TransactionTopic:指定要创建的 Topic 名称,这里使用 TransactionTopic 作为示例,可根据实际需求更改。
  • -c DefaultCluster:指定集群名称,这里使用 DefaultCluster,根据使用的集群进行修改。
  • -r 8:设置读队列的数量为 8,可以根据业务需求调整。
  • -w 8:设置写队列的数量为 8,同样可按需调整。

下面是一个使用 Java 代码实现事务消息的示例:

java 复制代码
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.TransactionListener;
import org.apache.rocketmq.client.producer.TransactionMQProducer;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageExt;

import java.util.concurrent.TimeUnit;

public class Producer {
    public static void main(String[] args) throws MQClientException, InterruptedException {
        // 创建一个事务生产者实例,指定生产者组名
        TransactionMQProducer producer = new TransactionMQProducer("TransactionTopicProducerGroup");
        // 设置NameServer的地址
        producer.setNamesrvAddr("localhost:9876");
        // 设置事务监听器
        producer.setTransactionListener(new TransactionListener() {
            @Override
            public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
                // 执行本地事务,这里简单模拟创建订单和扣减库存操作
                try {
                    // 模拟创建订单成功
                    System.out.println("创建订单成功");
                    // 模拟扣减库存成功
                    System.out.println("扣减库存成功");
                    return LocalTransactionState.COMMIT_MESSAGE;
                } catch (Exception e) {
                    // 本地事务执行失败,回滚事务
                    System.out.println("本地事务执行失败,回滚事务");
                    return LocalTransactionState.ROLLBACK_MESSAGE;
                }
            }

            @Override
            public LocalTransactionState checkLocalTransaction(MessageExt msg) {
                // 检查本地事务状态,这里简单返回COMMIT_MESSAGE表示事务已提交
                System.out.println("检查本地事务状态,事务已提交");
                return LocalTransactionState.COMMIT_MESSAGE;
            }
        });
        // 启动生产者
        producer.start();
        // 创建一条消息,指定主题、标签和消息体
        Message message = new Message("TransactionTopic", "*", "创建订单事务消息".getBytes());
        // 发送事务消息
        SendResult sendResult = producer.sendMessageInTransaction(message, null);
        System.out.println(sendResult);
        // 保持主线程运行,以便观察事务处理结果
        TimeUnit.MINUTES.sleep(5);
        // 关闭生产者
        producer.shutdown();
    }
}
java 复制代码
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;

import java.util.List;

public class Consumer {
    public static void main(String[] args) throws MQClientException {
        // 创建一个消费者实例,指定消费者组名
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("TransactionTopicConsumerGroup");
        // 设置NameServer的地址
        consumer.setNamesrvAddr("localhost:9876");
        // 订阅主题
        consumer.subscribe("TransactionTopic", "*");
        // 注册消息监听器,处理接收到的消息
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> messageList, ConsumeConcurrentlyContext context) {
                for (MessageExt msg : messageList) {
                    System.out.println(new String(msg.getBody()));
                }
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        // 启动消费者
        consumer.start();
    }
}

四、总结

RocketMQ 以其卓越的性能、丰富的特性和强大的功能,在分布式架构的舞台上大放异彩。它不仅为系统提供了高效的解耦能力,确保了各模块之间的独立运作,还在流量削峰填谷、消息可靠传输等方面发挥着关键作用。无论是普通消息的广泛应用,还是顺序消息对业务逻辑的严格保障;无论是定时 / 延时消息对任务调度的精准控制,还是事务消息对分布式事务一致性的有力维护,RocketMQ 都展现出了其作为一款优秀消息队列的独特魅力。

在当今数字化浪潮汹涌澎湃的时代,分布式架构的应用场景日益广泛,RocketMQ 的发展前景也极为广阔。随着云计算、大数据、人工智能等新兴技术的不断崛起,对消息队列的性能、可靠性和扩展性提出了更高的要求。RocketMQ 凭借其不断演进的技术和强大的社区支持,有望在这些领域中持续发挥重要作用,助力企业构建更加高效、稳定、智能的分布式系统 。

希望通过本文的介绍,能够激发大家对 RocketMQ 的浓厚兴趣,鼓励大家深入探索 RocketMQ 的更多奥秘。在实际项目中,大胆尝试运用 RocketMQ 的各种特性,解决复杂的业务问题,为分布式系统的构建贡献自己的智慧和力量。相信在 RocketMQ 的陪伴下,我们能够在分布式技术的海洋中乘风破浪,驶向更加美好的未来。

相关推荐
啊晚2 分钟前
ABP - 缓存模块(1)
后端·缓存·asp.net
胡尔摩斯.7 小时前
LoadBalancer负载均衡服务调用
java·后端·spring cloud·loadbalancer
编程|诗人8 小时前
T-SQL语言的数据库交互
开发语言·后端·golang
IT筱筱9 小时前
springboot集成websocket实现实时大量数据,效率性能高
spring boot·后端·websocket
续亮~9 小时前
RocketMQ 学习笔记01
笔记·学习·rocketmq
coding侠客9 小时前
线上工单引发的思考:Spring Boot 中 @Autowired 与 @Resource 的区别
java·spring boot·后端
爱学习的执念9 小时前
软件测试—接口测试面试题及jmeter面试题
软件测试·jmeter·面试·软件测试面试
vip1024p9 小时前
springboot集成onlyoffice(部署+开发)
java·spring boot·后端
秃了也弱了。10 小时前
springboot使用websocket
spring boot·后端·websocket
计算机-秋大田10 小时前
基于微信小程序教学辅助系统设计与实现(LW+源码+讲解)
java·后端·微信小程序·小程序·课程设计