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

手写rocketMQ教程:从零开始搭建RocketMQ入门指南

标签:
中间件
概述

本文详细介绍了RocketMQ生产者与消费者实例的创建过程,以及消息发送和接收的多种方式。通过手写RocketMQ教程,读者将全面了解RocketMQ的消息模型、消息类型以及路由机制。文章还涵盖了日志与异常处理、性能优化和集群运维等实用知识,旨在帮助读者更好地理解和应用RocketMQ的相关知识。

RocketMQ简介与环境搭建
什么是RocketMQ

RocketMQ是一款由阿里巴巴集团开源的分布式消息中间件,它基于高可用的设计理念,保证了数据的可靠传输,同时也具备良好的扩展性。RocketMQ支持多种消息模式,可以广泛应用于异步通信、解耦系统、流量削峰等领域。其设计初衷是为了满足阿里巴巴集团内部复杂的业务场景,因此在高并发、大数据量等复杂环境中表现出色。

RocketMQ主要由以下几个核心组件构成:

  • NameServer:负责维护Broker的元数据,提供对Broker的管理服务。
  • Broker:消息的转发和存储中间件,RocketMQ将接收的消息转发给对应的消费者,并将消息存储到本地磁盘。
  • Producer:消息的生产者,负责将消息发送到指定的Topic。
  • Consumer:消息的消费者,负责从指定的Topic中拉取消息并进行处理。
  • Client:客户端,包括生产者和消费者,它们通过NameServer与Broker进行交互。
快速开始:搭建RocketMQ环境
  1. 环境准备:确保已安装JDK 1.8及以上版本和 Maven 3.0+。RocketMQ不支持Java 9及以上版本。

  2. 下载RocketMQ:访问RocketMQ的GitHub仓库下载最新版本的源码。当前稳定版本为4.9.0。如下示例展示了如何下载并解压RocketMQ:
# 下载RocketMQ
wget https://github.com/apache/rocketmq/releases/download/v4.9.0/rocketmq-all-4.9.0-bin-release.zip

# 解压RocketMQ
unzip rocketmq-all-4.9.0-bin-release.zip
cd rocketmq-all-4.9.0/
  1. 启动NameServer:RocketMQ的消息传输需要依赖NameServer来提供路由服务,NameServer是一个无状态的服务,通常需要部署两个节点以提供高可用。启动NameServer的命令如下:
nohup sh bin/mqnamesrv &
  1. 启动Broker:接着,需要启动Broker。通常情况下,建议部署两个Broker节点来实现高可用。启动Broker的命令如下:
nohup sh bin/mqbroker -n localhost:9876 &
  1. 测试运行:启动完成后,可以通过发送一条消息来测试RocketMQ是否正常运行。使用如下命令发送一条消息到名为TestTopic的Topic:
sh bin/mqadmin topicCreate -n localhost:9876 TestTopic

sh bin/mqadmin ping -n localhost:9876

上述命令创建一个名为TestTopic的Topic,并通过ping命令检查NameServer是否正常运行。

  1. 关闭RocketMQ:如果需要关闭RocketMQ,可以使用以下命令来停止NameServer和Broker:
sh bin/mqnamesrv.stop
sh bin/mqbroker.stop -n localhost:9876
配置RocketMQ的基本参数

RocketMQ提供了配置文件来调整其行为,这些配置文件位于conf目录下。以下是一些常见的配置参数及其解释:

  • broker.conf:Broker配置文件,用于配置Broker的运行参数。例如,修改brokerNamebrokerClusterNamebrokerId等参数,可以调整Broker的集群名称、Broker名称和ID。
  • brokerrollback.conf:用于配置Broker的回滚参数,如autoCommitbroadcastIPs等,可以控制Broker在出现异常时的回滚行为。
  • logback.properites:配置RocketMQ的日志输出级别和格式,如logFilelogLevel等。
  • logback-broker.xml:Broker的日志配置文件,详细定义了Broker的日志输出格式。
  • logback-namesrv.xml:NameServer的日志配置文件,详细定义了NameServer的日志输出格式。
  • mqadmin.properties:用于配置RocketMQ管理命令的参数,如namesrvAddr等。

配置示例:

# broker.conf
brokerClusterName = DefaultCluster
brokerName = broker-0
brokerId = 0
namesrvAddr = localhost:9876
# logback.properites
logFile = ${user.home}/logs/rocketmqlogs
logLevel = INFO

通过编辑这些配置文件,可以实现对RocketMQ运行环境的优化和维护。

手写RocketMQ生产者与消费者
创建RocketMQ生产者实例

在创建RocketMQ生产者实例之前,首先需要创建一个Producer对象。在RocketMQ中,Producer类用于代表一个生产者实例,其主要功能是将消息发送到指定的Topic。下面是一个创建生产者实例的代码示例:

import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.common.protocol.namesrv.NamesrvAddressing;

// 创建生产者实例
DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");
producer.setNamesrvAddr("localhost:9876");
producer.setInstanceName("ProducerInstanceName");
producer.start();
发送消息的方法

RocketMQ支持多种消息发送方式,包括同步发送、异步发送和单向发送。不同发送方式的处理逻辑如下:

  • 同步发送:发送消息后,生产者会等待Broker的响应,确认消息是否已成功发送。这种方式适用于需要消息可靠性的场景。
  • 异步发送:发送消息后,生产者不会等待Broker的响应,而是通过回调函数来接收响应结果。这种方式适用于不需要等待消息发送结果的场景。
  • 单向发送:发送消息后,生产者既不会等待Broker的响应,也不会通过回调函数来接收响应结果。这种方式适用于不需要等待消息发送结果的场景,并且可以提高发送性能。

同步发送示例

public void sendMessageSync(String topic, String tag, String message) throws Exception {
    Message msg = new Message(topic, tag, message.getBytes(RemotingHelper.DEFAULT_CHARSET));
    SendResult sendResult = producer.send(msg);
    System.out.println("消息发送结果:" + sendResult);
}

异步发送示例

public void sendMessageAsync(String topic, String tag, String message) throws Exception {
    Message msg = new Message(topic, tag, message.getBytes(RemotingHelper.DEFAULT_CHARSET));
    producer.send(msg, new SendCallback() {
        @Override
        public void onSuccess(SendResult sendResult) {
            System.out.println("消息发送成功:" + sendResult);
        }

        @Override
        public void onException(Throwable e) {
            System.out.println("消息发送失败:" + e.getMessage());
        }
    });
}

单向发送示例

public void sendMessageOneWay(String topic, String tag, String message) {
    Message msg = new Message(topic, tag, message.getBytes(RemotingHelper.DEFAULT_CHARSET));
    producer.sendOneway(msg);
}
消息的接收与消费

在RocketMQ中,消息的接收与消费是通过Consumer类来实现的。Consumer类代表一个消费者实例,其主要功能是从指定的Topic中拉取消息并进行处理。消费者有两种接收消息的方式:拉模式和推模式。

  • 拉模式:消费者主动向Broker请求消息,这种方式适用于消费者需要主动拉取消息的场景。
  • 推模式:Broker主动将消息推送给消费者,这种方式适用于需要实时消费消息的场景。

创建消费者实例

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderedSuccess;
import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;

// 创建消费者实例
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroupName");
consumer.setNamesrvAddr("localhost:9876");
consumer.subscribe("TestTopic", "*");
consumer.setMessageModel(MessageModel.BROADCASTING);
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
consumer.registerMessageListener(new MessageListenerOrderly() {
    @Override
    public ConsumeOrderedResult consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
        for (MessageExt msg : msgs) {
            System.out.println("接收到的消息:" + new String(msg.getBody()));
        }
        return ConsumeOrderedResult.SUCCESS;
    }
});
consumer.start();

处理消费失败场景

如果消费过程中出现异常,可以通过返回RECONSUME_LATER来设置消息的重试机制。

consumer.setMessageListener(new MessageListenerConcurrently() {
    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
        try {
            // 处理消息
        } catch (Exception e) {
            // 处理消息消费失败
            return ConsumeConcurrentlyStatus.RECONSUME_LATER;
        }
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
});

使用顺序模式进行消息消费

在顺序模式下,消息按照顺序进行消费,适用于需要保证消息消费顺序的场景。

consumer.setMessageModel(MessageModel.CLUSTERING);
consumer.subscribe("TestTopic", "*");
consumer.setMessageListener(new MessageListenerOrderly() {
    @Override
    public ConsumeOrderedResult consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
        for (MessageExt msg : msgs) {
            System.out.println("接收到的消息:" + new String(msg.getBody()));
        }
        return ConsumeOrderedResult.SUCCESS;
    }
});
生产者与消费者的交互过程

在RocketMQ中,生产者与消费者的交互过程如下:

  1. 生产者发送消息:生产者将消息发送到指定的Topic。
  2. NameServer路由信息:NameServer维护了所有Broker的路由信息,生产者通过NameServer获取到消息的路由信息。
  3. Broker接收消息:Broker接收生产者发送的消息,并将其存储到本地磁盘。
  4. 消息路由:NameServer根据路由信息将消息转发给对应的消费者实例。
  5. 消费者拉取消息:消费者向Broker请求消息,Broker将消息推送给消费者,消费者接收到消息后进行处理。
  6. 消息确认:消费者处理完消息后,向Broker发送确认信息,Broker根据确认信息更新消息的状态。
RocketMQ消息模型与消息类型详解
RocketMQ的消息模型介绍

RocketMQ的消息模型主要分为两个方面:消息发布模式和消息消费模式。

消息发布模式

RocketMQ支持以下几种消息发布模式:

  • 单播:消息仅发送给单个消费者。
  • 广播:消息发送给所有消费者。
  • 集群:消息仅发送给一个订阅了该Topic的消费者。

消息消费模式

RocketMQ支持以下几种消息消费模式:

  • 集群模式:多个消费者实例同时消费消息,每个消息只被一个消费者实例消费,适用于需要并行处理消息的场景。
  • 顺序模式:消息按照顺序进行消费,适用于需要保证消息消费顺序的场景。
了解不同消息类型:同步消息、异步消息、单向消息

在RocketMQ中,消息类型主要分为同步消息、异步消息和单向消息。

  • 同步消息:发送消息后,生产者会等待Broker的响应,确认消息是否已成功发送,适用于需要保证消息可靠性的场景。
  • 异步消息:发送消息后,生产者不会等待Broker的响应,通过回调函数来接收响应结果,适用于不需要等待消息发送结果的场景。
  • 单向消息:发送消息后,生产者既不会等待Broker的响应,也不会通过回调函数来接收响应结果,适用于不需要等待消息发送结果的场景,并且可以提高发送性能。
创建并发送不同类型的RocketMQ消息

同步消息发送示例

public void sendMessageSync(String topic, String tag, String message) throws Exception {
    Message msg = new Message(topic, tag, message.getBytes(RemotingHelper.DEFAULT_CHARSET));
    SendResult sendResult = producer.send(msg);
    System.out.println("消息发送结果:" + sendResult);
}

异步消息发送示例

public void sendMessageAsync(String topic, String tag, String message) throws Exception {
    Message msg = new Message(topic, tag, message.getBytes(RemotingHelper.DEFAULT_CHARSET));
    producer.send(msg, new SendCallback() {
        @Override
        public void onSuccess(SendResult sendResult) {
            System.out.println("消息发送成功:" + sendResult);
        }

        @Override
        public void onException(Throwable e) {
            System.out.println("消息发送失败:" + e.getMessage());
        }
    });
}

单向消息发送示例

public void sendMessageOneWay(String topic, String tag, String message) {
    Message msg = new Message(topic, tag, message.getBytes(RemotingHelper.DEFAULT_CHARSET));
    producer.sendOneway(msg);
}

处理消息超时和重试策略

当消息发送超时时,生产者可以设置重试策略来自动尝试重新发送消息。

producer.setRetryTimesWhenSendFailed(2); // 设置重试次数
producer.setSendMsgTimeout(3000); // 设置超时时间
消息的过滤与路由机制
实现消息过滤的方法

RocketMQ支持多种消息过滤机制,包括标签过滤和SQL92过滤。

标签过滤

标签过滤是通过消息的标签(Tag)来实现的。生产者可以为每条消息指定一个Tag,消费者可以在订阅时指定一个或多个Tag,只有符合订阅Tag的消息才会被消费。

// 创建消费者实例并订阅指定标签的消息
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroupName");
consumer.setNamesrvAddr("localhost:9876");
consumer.subscribe("TestTopic", "TagA");
consumer.setMessageListener(new MessageListenerConcurrently() {
    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
        for (MessageExt msg : msgs) {
            System.out.println("接收到的消息:" + new String(msg.getBody()));
        }
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
});
consumer.start();

SQL92过滤

SQL92过滤是通过SQL92查询语句来实现的。生产者可以为每条消息指定一个属性(Key),消费者可以在订阅时指定一个SQL92查询语句,只有符合查询语句的消息才会被消费。

// 创建消费者实例并订阅符合SQL92查询语句的消息
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroupName");
consumer.setNamesrvAddr("localhost:9876");
consumer.subscribe("TestTopic", "select * from TestTopic where Key='ValueA'");
consumer.setMessageListener(new MessageListenerConcurrently() {
    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
        for (MessageExt msg : msgs) {
            System.out.println("接收到的消息:" + new String(msg.getBody()));
        }
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
});
consumer.start();
路由机制详解与实践

RocketMQ的路由机制是通过NameServer来实现的。NameServer负责维护Broker的元数据,并将Broker的路由信息提供给生产者和消费者。当生产者发送消息时,NameServer会根据路由信息将消息转发给相应的Broker;当消费者拉取消息时,NameServer也会根据路由信息将消息推送给相应的消费者。

路由信息的更新

NameServer会定期从Broker获取新的路由信息,并将这些信息保存到本地缓存中。当生产者或消费者请求路由信息时,NameServer会从本地缓存中返回最新的路由信息。

import org.apache.rocketmq.common.protocol.namesrv.NamesrvAddressing;
import org.apache.rocketmq.remoting.server.NameServerStartup;

// 启动NameServer并更新路由信息
NamesrvAddressing ns = new NamesrvAddressing();
NameServerStartup nsStartup = new NameServerStartup();
nsStartup.start(9876, ns);

路由信息的同步

当Broker发生变化时(例如新增或删除Broker),NameServer会将这些变化同步到其他NameServer节点,以确保所有NameServer节点上的路由信息都是最新的。

import org.apache.rocketmq.remoting.netty.NettyServerConfig;
import org.apache.rocketmq.remoting.netty.NettyRemotingServer;

// 启动NameServer并同步路由信息
NettyServerConfig serverConfig = new NettyServerConfig();
serverConfig.setListenPort(9876);
NettyRemotingServer server = new NettyRemotingServer(serverConfig);
server.start();
日志与异常处理
RocketMQ日志文件介绍

RocketMQ的日志文件主要用于记录系统运行状态和问题排查。RocketMQ的日志文件分为两类:Broker日志文件和NameServer日志文件。这两类日志文件分别位于logs目录下。

  • Broker日志文件:记录Broker的运行状态,包括消息的发送和接收情况、系统资源使用情况等。
  • NameServer日志文件:记录NameServer的运行状态,包括路由信息的变化情况、系统资源使用情况等。
# Broker日志文件路径
logs/broker.log

# NameServer日志文件路径
logs/namesrv.log
常见错误与异常处理

RocketMQ在运行过程中可能会遇到各种错误和异常,以下是一些常见的错误和异常处理方法:

  • 消息发送失败:当消息发送失败时,可以通过调用producer.send(msg)方法的返回值来获取失败原因,并根据失败原因进行重试或处理。
SendResult sendResult = producer.send(msg);
if (sendResult.getSendStatus() != SendStatus.SEND_OK) {
    // 处理消息发送失败
}
  • 消息消费失败:当消息消费失败时,可以通过设置消费回调函数来处理失败情况,并根据失败原因进行重试或处理。
consumer.setMessageListener(new MessageListenerConcurrently() {
    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
        try {
            // 处理消息
        } catch (Exception e) {
            // 处理消息消费失败
            return ConsumeConcurrentlyStatus.RECONSUME_LATER;
        }
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
});
日志解析与调试技巧

RocketMQ的日志文件包含了系统运行状态和错误信息,通过解析日志文件可以快速定位问题。以下是一些日志解析和调试技巧:

  • 定位错误日志:通过搜索关键字(如ERRORException)来快速定位错误日志。
  • 查看系统状态:通过查看系统资源使用情况(如CPU、内存、磁盘空间等)来判断系统是否正常运行。
  • 检查配置文件:通过检查配置文件(如broker.conflogback.properites)来确保配置正确。
# 搜索错误日志
grep "ERROR" logs/broker.log
# 检查配置文件
cat conf/broker.conf
性能优化与集群运维
RocketMQ性能优化技巧

RocketMQ的性能优化主要从以下几个方面进行:

  1. 合理设置参数:通过调整生产者和消费者的参数(如batchSendEnablemaxMessageSizepullBatchSize等)来提高消息发送和消费的性能。
  2. 优化路由信息:通过优化NameServer的路由信息(如减少路由信息的更新频率、优化路由信息的同步机制等)来提高系统的可用性和性能。
  3. 使用消息压缩:通过使用消息压缩(如gzip压缩)来减少消息的大小,从而提高消息发送和消费的性能。
# 启用批量发送
brokerConfig.setBatchSendEnable(true);

# 设置最大消息大小
producer.setMaxMessageSize(1024 * 1024);

# 设置批量拉取消息的大小
consumer.setPullBatchSize(100);
集群运维与维护的基础知识

RocketMQ的集群运维与维护主要包括以下几个方面:

  1. 监控系统:通过监控系统(如RocketMQ自带的监控工具mqadmin)来实时监控系统的运行状态,及时发现和处理问题。
  2. 备份与恢复:通过定期备份数据(如消息和配置文件)来防止数据丢失,并在需要时进行数据恢复。
  3. 扩容与缩容:根据业务需求对集群进行扩容或缩容,以满足不同的业务场景需求。
# 监控Broker的运行状态
sh bin/mqadmin brokerList -n localhost:9876

# 备份Broker的数据
tar -czvf broker_data_backup.tar.gz -C /opt/rocketmq/broker/data .

# 恢复Broker的数据
tar -xzvf broker_data_backup.tar.gz -C /opt/rocketmq/broker/data
点击查看更多内容
TA 点赞

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

评论

作者其他优质文章

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

100积分直接送

付费专栏免费学

大额优惠券免费领

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

举报

0/150
提交
取消