为了账号安全,请及时绑定邮箱和手机立即绑定

RocketMQ消息中间件项目实战教程

标签:
杂七杂八
概述

本文详细介绍了RocketMQ消息中间件的安装配置、基本概念、消息发送与接收流程,并通过实战案例展示了RocketMQ在项目中的应用。通过学习,读者可以掌握RocketMQ消息中间件项目实战的关键步骤和技巧,确保消息的可靠传输和高效处理。

RocketMQ简介与安装配置

RocketMQ的基本概念

RocketMQ是由阿里巴巴开放源代码的分布式消息中间件,它具有高吞吐、低延迟、可靠传输及大规模系统支持等特点。RocketMQ采用主从模式,由主服务器提供服务,并由从服务器进行数据同步,保证数据的可靠性和持久化。

  • 主服务器(Broker):主服务器负责处理客户端发送过来的消息,将消息写入磁盘或者内存中,并提供读取消息的服务。
  • 从服务器(Slave):从服务器负责从主服务器同步数据,并在主服务器不可用时接替主服务器的角色。
  • 名称服务器(Name Server):名称服务器负责接受 Broker 的注册信息,并提供客户端对于 Broker 的寻址服务。
  • 生产者(Producer):生产者用于生产消息,将消息通过网络发送给 RocketMQ 集群。
  • 消费者(Consumer):消费者用于消费消息,从 RocketMQ 集群拉取消息进行处理。

安装RocketMQ步骤详解

  1. 下载RocketMQ
    首先,访问RocketMQ的GitHub仓库,下载RocketMQ的最新版本:

    git clone https://github.com/apache/rocketmq.git
    cd rocketmq
  2. 环境依赖配置
    RocketMQ需要JDK 1.8及以上版本,所以请确保已经安装了JDK:

    java -version

    若未安装,可通过以下步骤安装:

    sudo apt update
    sudo apt install openjdk-8-jdk
  3. 启动Name Server
    Name Server是RocketMQ的重要组成部分,负责路由信息的管理,支持集群的动态扩展。

    cd ~/rocketmq/rocketmq-all-4.9.2/bin
    sh mqnamesrv &
  4. 启动Broker
    Broker主要负责消息的存储、转发和消费过程中的异常处理,有Master和Slave两种角色。这里我们启动Master Broker:

    sh mqbroker -c ~/rocketmq/rocketmq-all-4.9.2/conf/2m-n1-async/broker-a.properties &
  5. 验证安装
    访问http://localhost:9876,如果可以看到Name Server注册的Broker信息,则安装成功。

RocketMQ的配置方法

RocketMQ的配置文件主要位于conf目录下,包括broker.propertieslogback等文件,其中最核心的配置文件为broker.properties

  1. broker.properties

    brokerClusterName=DefaultCluster
    brokerName=Broker-a
    brokerId=0
    deleteWhen=04
    fileReservedTime=72
    pollMaxBytes=1024
    mapedFileSizeCommitLog=104857600
    mapedFileSizeConsumeQueue=33554432
    storeDay=7
    • brokerClusterName:指定了broker所在的集群名。
    • brokerName:指定了broker的名字,必须全局唯一。
    • brokerId:指定了broker的id,0为Master,非0为Slave。
    • deleteWhen:指定了删除消息的时间,04表示每天凌晨4点删除过期消息。
    • fileReservedTime:指定了文件保留时间,单位为天。
    • pollMaxBytes:指定了每次拉取的最大值,单位为字节。
    • mapedFileSizeCommitLog:指定了commitlog的mapedfile大小,用于存储消息。
    • mapedFileSizeConsumeQueue:指定了consumequeue的mapedfile大小,用于存储每条消息的偏移量。
    • storeDay:指定了消息存储的天数。
  2. logback.xml
    <configuration>
       <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
           <encoder>
               <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
           </encoder>
       </appender>
       <appender name="FILE" class="ch.qos.logback.core.FileAppender">
           <file>logs/rocketmq.log</file>
           <encoder>
               <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
           </encoder>
       </appender>
       <root level="info">
           <appender-ref ref="STDOUT" />
           <appender-ref ref="FILE" />
       </root>
    </configuration>
    • appender:指定了日志输出方式,可以是控制台输出或文件输出。
    • encoder:指定了日志格式。
    • file:指定了日志文件路径。
    • root:指定了根日志级别,这里设置为info
RocketMQ基本概念解析

主题与队列的理解

RocketMQ中的主题(Topic)与队列(Queue)是消息分类的基础概念。主题主要用于分类消息,可以理解为消息的分类标签,例如stockorder等。而队列则是主题下的具体消息存储单元,每个主题可以有多个队列,每个消息只能属于一个队列。

主题(Topic

主题可以看作是消息的分类标签,用于标识不同类型的消息。例如,一个电子商务系统中可以定义stock主题来标识库存相关消息,定义order主题来标识订单相关消息。

队列(Queue

每个主题可以包含多个队列,队列主要用于存储不同类型的实例消息。例如,Topic=stock, QueueId=0表示库存消息中的第一个队列,Topic=stock, QueueId=1表示库存消息中的第二个队列。

生产者与消费者的角色区分

生产者(Producer)用于生产消息,消费者(Consumer)用于消费消息。在RocketMQ中,生产者负责将消息通过网络发送给RocketMQ集群,消费者负责从RocketMQ集群拉取消息进行处理。

生产者(Producer

生产者的主要任务是将消息发送到RocketMQ集群中的指定主题。生产者可以是同步发送或异步发送,同步发送是指发送消息后等待消息发送结果,异步发送是指发送消息后直接返回,不会等待发送结果。

消费者(Consumer

消费者的主要任务是拉取消息并进行处理。消费者可以是订阅一个主题,也可以订阅多个主题,订阅一个主题时,可以使用多个消费者实例来处理不同的队列,以实现并发消费。

消息发送与接收的流程

消息发送与接收流程可以分为以下几步:

  1. 生产者发送消息

    • 生产者发送消息到指定的主题,并选择合适的队列。
    • RocketMQ集群接收到消息后,将消息存储到指定的队列中。
  2. 消费者拉取消息
    • 消费者订阅指定的主题,并选择合适的队列进行消费。
    • RocketMQ集群将消息从指定的队列中拉取并发送给消费者进行处理。
RocketMQ消息发送实战

生产者代码实现

生产者生产消息到RocketMQ集群中,代码实现如下:

import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;

public class RocketMQProducer {
    public static void main(String[] args) throws Exception {
        // 创建生产者实例
        DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");
        producer.setNamesrvAddr("localhost:9876");

        // 启动生产者
        producer.start();

        // 创建消息
        Message msg = new Message("TopicTest", // topic
                                  "TagA", // tag
                                  ("Hello RocketMQ").getBytes(RemotingHelper.DEFAULT_CHARSET), // body
                                  null // 例如:指定消息的key
                                 );

        // 发送消息
        SendResult sendResult = producer.send(msg);

        // 打印发送结果
        System.out.printf("%s%n", sendResult);

        // 关闭生产者
        producer.shutdown();
    }
}

异步发送与同步发送的对比

在RocketMQ中,发送消息有同步发送和异步发送两种模式:

  1. 同步发送

    • SendResult result = producer.send(msg);
    • 这种方式会等待消息发送完成并返回结果,适合需要保证消息发送成功的情况。
  2. 异步发送
    • producer.send(msg, new SendCallback() { ... });
    • 这种方式会立即返回,不需要等待消息发送完成,适用于不需要等待消息发送结果的情况。

发送消息的常见问题与解决方法

  1. 网络问题

    • 问题:消息发送时出现网络错误。
    • 解决:检查网络连接,确保RocketMQ服务器和客户端网络畅通。
  2. 消息大小限制

    • 问题:发送的消息过大,超出限制。
    • 解决:调整消息大小,使其符合RocketMQ的限制。
  3. 主题不存在

    • 问题:发送消息时指定的主题不存在。
    • 解决:确保主题已创建或已订阅。
  4. 发送超时
    • 问题:消息发送超时。
    • 解决:调整发送超时时间设置。
RocketMQ消息接收实战

消费者的代码实现

消费者从RocketMQ集群中拉取消息并进行处理,代码实现如下:

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderedSuccess;
import org.apache.rocketmq.client.consumer.listener.MessageQueue;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;

public class RocketMQConsumer {
    public static void main(String[] args) throws Exception {
        // 创建消费者实例
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroupName");
        consumer.setNamesrvAddr("localhost:9876");

        // 订阅主题和标签
        consumer.subscribe("TopicTest", "TagA");

        // 设置从队列头部开始消费
        consumer.setMessageModel(MessageModel.BROADCASTING);
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);

        // 注册消息监听器
        consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
            for (MessageExt msg : msgs) {
                System.out.println(new String(msg.getBody()));
            }
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        });

        // 启动消费者
        consumer.start();

        // 等待关闭消费者
        System.in.read();
    }
}

接收消息的模式选择

RocketMQ支持两种消息接收模式:广播模式和集群模式。

  1. 广播模式(MessageModel.BROADCASTING

    • 所有消费者都会收到消息,适用于消息需要被所有消费者处理的场景。
  2. 集群模式(MessageModel.CLUSTERING
    • 每条消息只会被某个消费者处理,适用于消息需要被唯一消费者处理的场景。

消费者的消息处理逻辑

消费者的消息处理逻辑可以根据业务需求进行定制,常见的处理逻辑包括:

  1. 消息解析

    • 消息到达后,消费者需要解析消息内容,获取需要的信息。
  2. 消息存储

    • 根据业务需求,将消息存储到数据库或其他持久化存储中。
  3. 消息处理

    • 根据消息内容执行相应的业务逻辑,如更新库存、创建订单等。
  4. 消息回溯
    • 当消息处理失败时,可以设置消息回溯机制,重新处理失败的消息。
RocketMQ项目实战案例

实战案例背景介绍

假设我们有一个电子商务系统,需要实现库存管理和订单处理的功能。库存管理系统需要实时更新库存信息,订单系统需要实时处理订单信息。为了保证信息的实时性和可靠性,我们选择使用RocketMQ作为消息中间件。

项目需求分析

  1. 库存管理系统

    • 发送库存更新消息,消息内容包含库存编号和库存数量。
    • 接收库存更新消息,更新库存信息。
  2. 订单管理系统
    • 发送订单创建消息,消息内容包含订单编号和数量。
    • 接收订单创建消息,创建订单信息。

代码实现与调试

库存管理系统生产者代码实现

import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;

public class StockProducer {
    public static void main(String[] args) throws Exception {
        // 创建生产者实例
        DefaultMQProducer producer = new DefaultMQProducer("StockProducerGroup");
        producer.setNamesrvAddr("localhost:9876");

        // 启动生产者
        producer.start();

        // 创建消息
        Message msg = new Message("StockTopic", // topic
                                  "StockTag", // tag
                                  ("StockId:1001,StockCount:50").getBytes(RemotingHelper.DEFAULT_CHARSET), // body
                                  null // 例如:指定消息的key
                                 );

        // 发送消息
        SendResult sendResult = producer.send(msg);

        // 打印发送结果
        System.out.printf("%s%n", sendResult);

        // 关闭生产者
        producer.shutdown();
    }
}

库存管理系统消费者代码实现

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderedSuccess;
import org.apache.rocketmq.client.consumer.listener.MessageQueue;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;

public class StockConsumer {
    public static void main(String[] args) throws Exception {
        // 创建消费者实例
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("StockConsumerGroup");
        consumer.setNamesrvAddr("localhost:9876");

        // 订阅主题和标签
        consumer.subscribe("StockTopic", "StockTag");

        // 设置从队列头部开始消费
        consumer.setMessageModel(MessageModel.BROADCASTING);
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);

        // 注册消息监听器
        consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
            for (MessageExt msg : msgs) {
                System.out.println(new String(msg.getBody()));
                // 更新库存信息
                updateStockInfo(new String(msg.getBody()));
            }
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        });

        // 启动消费者
        consumer.start();

        // 等待关闭消费者
        System.in.read();
    }

    private static void updateStockInfo(String msgBody) {
        // 例如:更新库存信息
        System.out.println("Updating stock info: " + msgBody);
    }
}

订单管理系统生产者代码实现

import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;

public class OrderProducer {
    public static void main(String[] args) throws Exception {
        // 创建生产者实例
        DefaultMQProducer producer = new DefaultMQProducer("OrderProducerGroup");
        producer.setNamesrvAddr("localhost:9876");

        // 启动生产者
        producer.start();

        // 创建消息
        Message msg = new Message("OrderTopic", // topic
                                  "OrderTag", // tag
                                  ("OrderId:1001,OrderCount:5").getBytes(RemotingHelper.DEFAULT_CHARSET), // body
                                  null // 例如:指定消息的key
                                 );

        // 发送消息
        SendResult sendResult = producer.send(msg);

        // 打印发送结果
        System.out.printf("%s%n", sendResult);

        // 关闭生产者
        producer.shutdown();
    }
}

订单管理系统消费者代码实现

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderedSuccess;
import org.apache.rocketmq.client.consumer.listener.MessageQueue;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;

public class OrderConsumer {
    public static void main(String[] args) throws Exception {
        // 创建消费者实例
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("OrderConsumerGroup");
        consumer.setNamesrvAddr("localhost:9876");

        // 订阅主题和标签
        consumer.subscribe("OrderTopic", "OrderTag");

        // 设置从队列头部开始消费
        consumer.setMessageModel(MessageModel.BROADCASTING);
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);

        // 注册消息监听器
        consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
            for (MessageExt msg : msgs) {
                System.out.println(new String(msg.getBody()));
                // 创建订单信息
                createOrder(new String(msg.getBody()));
            }
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        });

        // 启动消费者
        consumer.start();

        // 等待关闭消费者
        System.in.read();
    }

    private static void createOrder(String msgBody) {
        // 例如:创建订单信息
        System.out.println("Creating order info: " + msgBody);
    }
}

调试

在实际开发中,可以根据需要进行单元测试、集成测试等,确保各个模块之间的正确性和稳定性。

  • 单元测试

    • 测试单个模块的功能,例如生产者发送消息、消费者接收消息等。
  • 集成测试
    • 测试多个模块之间的交互,例如库存管理系统和订单管理系统之间的消息传递。
RocketMQ常见问题与优化策略

常见异常及解决方法

  1. 网络问题

    • 问题:生产者或消费者与RocketMQ服务器之间网络不通。
    • 解决:检查网络配置,确保网络连接正常。
    • 例如:检查服务器防火墙配置,确保端口开放。
  2. 消息发送失败

    • 问题:生产者发送消息失败,可能的原因包括消息内容不符合规范、消息大小超过限制等。
    • 解决:检查消息内容,确保消息格式正确,调整消息大小。
  3. 消息接收失败

    • 问题:消费者接收消息失败,可能的原因包括主题不存在、标签设置错误等。
    • 解决:检查消费者订阅的主题和标签,确保订阅信息正确。
  4. 性能问题
    • 问题:消息发送和接收速度缓慢。
    • 解决:优化消息格式,减少消息大小;增加网络带宽,提高网络传输效率。

性能优化建议

  1. 消息格式优化

    • 减少消息大小,压缩消息内容。
    • 例如:使用序列化库如Kryo进行消息序列化。
  2. 网络优化

    • 增加网络带宽,提高网络传输速度。
    • 例如:使用专线或光纤连接RocketMQ服务器。
  3. 配置优化
    • 调整RocketMQ配置文件,优化消息存储和传输效率。
    • 例如:调整broker.properties文件中的deleteWhenfileReservedTime配置。

消息可靠传递机制

RocketMQ提供了多种机制来保证消息的可靠传递:

  1. 事务消息

    • 事务消息保证消息的可靠性和一致性,适用于需要严格保证消息传递顺序和消息一致性的场景。
    • 代码示例:

      import org.apache.rocketmq.client.producer.TransactionMQProducer;
      import org.apache.rocketmq.common.message.Message;
      
      public class TransactionProducer {
       public static void main(String[] args) throws Exception {
           // 创建生产者实例
           TransactionMQProducer producer = new TransactionMQProducer();
           producer.setNamesrvAddr("localhost:9876");
           producer.setTransactionCheckListener(new DefaultTransactionCheckListener());
      
           // 启动生产者
           producer.start();
      
           // 创建消息
           Message msg = new Message("TopicTest", // topic
                                     "TagA", // tag
                                     ("Hello RocketMQ").getBytes(RemotingHelper.DEFAULT_CHARSET), // body
                                     null // 例如:指定消息的key
                                    );
      
           // 发送事务消息
           producer.sendMessageInTransaction(msg, null);
      
           // 关闭生产者
           producer.shutdown();
       }
      }
  2. 消息重试机制

    • 通过设置消息重试次数,确保消息在发送失败时可以重新发送。
    • 代码示例:

      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.common.RemotingHelper;
      
      public class RetryProducer {
       public static void main(String[] args) throws Exception {
           // 创建生产者实例
           DefaultMQProducer producer = new DefaultMQProducer("RetryProducerGroup");
           producer.setNamesrvAddr("localhost:9876");
           producer.setRetryTimesWhenSendFailed(10);
      
           // 启动生产者
           producer.start();
      
           // 创建消息
           Message msg = new Message("TopicTest", // topic
                                     "TagA", // tag
                                     ("Hello RocketMQ").getBytes(RemotingHelper.DEFAULT_CHARSET), // body
                                     null // 例如:指定消息的key
                                    );
      
           // 发送消息
           SendResult sendResult = producer.send(msg);
      
           // 打印发送结果
           System.out.printf("%s%n", sendResult);
      
           // 关闭生产者
           producer.shutdown();
       }
      }

通过以上介绍和实践示例,希望读者能够更加深入了解RocketMQ消息中间件的基本概念、安装配置、消息发送与接收流程以及项目实战案例。同时,通过性能优化建议和可靠传递机制,可以更好地提升RocketMQ在实际项目中的表现。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消