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

手写RocketMQ资料:从入门到实践的全流程指南

标签:
中间件
概述

本文详细介绍了RocketMQ的环境搭建、消息发送与接收的基础知识,同时提供了丰富的代码示例和实际应用案例,旨在帮助读者深入理解RocketMQ的工作原理和使用方法。手写RocketMQ资料涵盖了从基础概念到高级功能的全面解析,帮助开发者快速上手并优化RocketMQ的使用体验。

RocketMQ简介与环境搭建

RocketMQ是什么

RocketMQ是一款由阿里巴巴开源的分布式消息中间件,主要提供高吞吐量、高可用性的消息传输服务。它基于轻量级的消息模型,实现了跨数据中心的可靠性传输与流量削峰。RocketMQ运用了高可用、高性能的设计理念,具有丰富的消息路由、过滤、消息堆积等特性,适用于多种分布式应用场景。

环境准备与安装

系统需求

  • 操作系统:支持Linux、Windows
  • Java环境:JDK 1.8及以上版本
  • Maven:用于构建RocketMQ项目

安装步骤

  1. 下载RocketMQ源码包,使用Git或其他方式从GitHub上获取代码。
  2. 解压源码包,使用Maven工具进行编译,生成RocketMQ的可执行文件。
git clone https://github.com/apache/rocketmq.git
cd rocketmq
mvn clean install -DskipTests
  1. 启动RocketMQ服务,进入RocketMQ解压后的bin目录,分别运行以下命令启动名为server的日志服务和namesrv服务。
nohup sh bin/mqnamesrv &
nohup sh bin/mqbroker -n 127.0.0.1:9876 &

验证安装

运行以下Python脚本,检查RocketMQ是否正常启动。

import subprocess

def check_server():
    process = subprocess.Popen(['ps', '-ef'], stdout=subprocess.PIPE)
    output, error = process.communicate()
    if error:
        print("Error occurred while checking RocketMQ server: ", error)
    else:
        stdout = output.decode('utf-8')
        if "org.apache.rocketmq.namesrv.NamesrvStartup" in stdout:
            print("RocketMQ nameserver is running.")
        if "org.apache.rocketmq.broker.BrokerRun" in stdout:
            print("RocketMQ broker is running.")
        else:
            print("RocketMQ server is not running.")

check_server()

配置文件示例

配置文件conf/broker.properties中包含一些重要的配置选项,如Broker的IP地址、端口号等。以下是一些基本配置示例:

brokerClusterName=DefaultCluster
brokerName=broker-a
brokerId=0
brokerRole=ASYNC_MASTER
listenPort=10911
namesrvAddr=127.0.0.1:9876
快速开始指南

以下是一个快速入门示例,展示如何使用RocketMQ发送和接收消息。

发送消息示例

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 Producer {
    public static void main(String[] args) throws Exception {
        // 创建生产者,设置生产者组名
        DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");
        // 设置NameServer地址
        producer.setNamesrvAddr("127.0.0.1:9876");
        // 启动生产者
        producer.start();
        // 创建消息
        Message msg = new Message("TestTopic", // topic
                "TagA", // tag
                "OrderID188", // key
                ("Hello RocketMQ.").getBytes(RemotingHelper.DEFAULT_CHARSET)); // body
        // 发送消息
        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.MessageListenerConcurrently;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;

import java.util.List;

public class Consumer {
    public static void main(String[] args) throws Exception {
        // 创建消费者,设置消费者组名
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroupName");
        // 设置NameServer地址
        consumer.setNamesrvAddr("127.0.0.1:9876");
        // 订阅主题和tag
        consumer.subscribe("TestTopic", "TagA");
        // 设置从何处消费
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
        // 注册消息监听器
        consumer.registerMessageListener((List<MessageExt> msgs, ConsumeOrderlyContext context) -> {
            for (MessageExt msg : msgs) {
                System.out.printf("Received message: %s%n", new String(msg.getBody()));
            }
            return ConsumeOrderlyStatus.SUCCESS;
        });
        // 启动消费者
        consumer.start();
        System.out.println("Consumer started.");
    }
}
消息发送与接收基础

发送消息的步骤详解

消息发送的过程包括创建生产者实例、设置生产者组名、设置NameServer地址、启动生产者、创建消息、发送消息、关闭生产者。下面逐个步骤进行说明。

  1. 创建生产者实例
    DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");
  2. 设置NameServer地址
    producer.setNamesrvAddr("127.0.0.1:9876");
  3. 启动生产者
    producer.start();
  4. 创建消息
    Message msg = new Message("TestTopic", // topic
        "TagA", // tag
        "OrderID188", // key
        ("Hello RocketMQ.").getBytes(RemotingHelper.DEFAULT_CHARSET)); // body
  5. 发送消息
    SendResult sendResult = producer.send(msg);
  6. 关闭生产者
    producer.shutdown();

接收消息的实践操作

消息接收主要是通过创建消费者实例、设置消费者组名、订阅主题和tag、注册消息监听器、启动消费者来实现。以下是详细的步骤说明。

  1. 创建消费者实例
    DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroupName");
  2. 设置NameServer地址
    consumer.setNamesrvAddr("127.0.0.1:9876");
  3. 订阅主题和tag
    consumer.subscribe("TestTopic", "TagA");
  4. 注册消息监听器
    consumer.registerMessageListener((List<MessageExt> msgs, ConsumeOrderlyContext context) -> {
    for (MessageExt msg : msgs) {
        System.out.printf("Received message: %s%n", new String(msg.getBody()));
    }
    return ConsumeOrderlyStatus.SUCCESS;
    });
  5. 启动消费者
    consumer.start();

消息发送与接收的注意事项

  1. 发送消息时需要设置生产者组名和NameServer地址,确保这些配置正确。
  2. 消息的topic和tag必须与接收方一致,否则接收方无法接收到消息。
  3. 发送方和接收方需要保持网络连接稳定,避免网络故障导致的消息丢失。
  4. 消息发送频繁时,考虑使用批量发送以提高性能。
  5. 消息消费时可能出现重复消费,需要保证业务逻辑的幂等性。
消息过滤与批量发送示例

消息过滤示例

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext;
import org.apache.rocketmq.common.message.MessageExt;

import java.util.List;

public class ConsumerWithFilter {
    public static void main(String[] args) throws Exception {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroup");
        consumer.setNamesrvAddr("127.0.0.1:9876");
        consumer.subscribe("TestTopic", "*");

        consumer.registerMessageListener((List<MessageExt> msgs, ConsumeOrderlyContext context) -> {
            for (MessageExt msg : msgs) {
                String tag = msg.getTopic() + ":" + msg.getTag();
                if (tag.equals("TestTopic:TagA")) {
                    System.out.printf("Received message: %s%n", new String(msg.getBody()));
                } else {
                    System.out.println("Message filtered out.");
                }
            }
            return ConsumeOrderlyStatus.SUCCESS;
        });

        consumer.start();
        System.out.println("Consumer started with message filtering.");
    }
}

批量发送消息示例

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

public class ProducerWithBatch {
    public static void main(String[] args) throws Exception {
        DefaultMQProducer producer = new DefaultMQProducer("ProducerGroup");
        producer.setNamesrvAddr("127.0.0.1:9876");
        producer.start();

        Message[] msgs = new Message[10];
        for (int i = 0; i < 10; i++) {
            msgs[i] = new Message("TestTopic", // topic
                    "TagA", // tag
                    "OrderID" + i, // key
                    ("Hello RocketMQ batch " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
        }

        SendResult sendResult = producer.send(msgs);
        System.out.printf("SendResult: %s%n", sendResult);

        producer.shutdown();
    }
}
实际案例分析与应用

实际项目中的应用案例分析

假设有一个电商网站,需要处理大量订单请求。使用RocketMQ可以实现订单请求的异步处理,提高系统性能。

  1. 订单生成
    • 用户下单后,订单信息通过RocketMQ异步发送到订单服务。
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 OrderProducer {
    public static void main(String[] args) throws Exception {
        DefaultMQProducer producer = new DefaultMQProducer("OrderProducerGroup");
        producer.setNamesrvAddr("127.0.0.1:9876");
        producer.start();

        Message msg = new Message("OrderTopic", // topic
                "OrderTag", // tag
                "OrderID123", // key
                ("Order information").getBytes(RemotingHelper.DEFAULT_CHARSET)); // body
        SendResult sendResult = producer.send(msg);
        System.out.printf("Order sent: %s%n", sendResult);

        producer.shutdown();
    }
}
  1. 库存减少
    • 订单服务接收到订单信息,同步库存服务减少相应库存。
public class InventoryService {
    public void decreaseInventory(String orderId) {
        // 逻辑处理代码
        System.out.println("Inventory decreased for order: " + orderId);
    }
}
  1. 支付确认
    • 订单服务基于RocketMQ通知支付系统进行支付确认。
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 PaymentProducer {
    public static void main(String[] args) throws Exception {
        DefaultMQProducer producer = new DefaultMQProducer("PaymentProducerGroup");
        producer.setNamesrvAddr("127.0.0.1:9876");
        producer.start();

        Message msg = new Message("PaymentTopic", // topic
                "PaymentTag", // tag
                "OrderID123", // key
                ("Payment confirmation").getBytes(RemotingHelper.DEFAULT_CHARSET)); // body
        SendResult sendResult = producer.send(msg);
        System.out.printf("Payment confirmation sent: %s%n", sendResult);

        producer.shutdown();
    }
}
  1. 订单完成
    • 支付系统确认支付后,同步订单服务,完成订单。
public class OrderService {
    public void completeOrder(String orderId) {
        // 逻辑处理代码
        System.out.println("Order completed for: " + orderId);
    }
}

RocketMQ在不同场景下的使用技巧

  1. 流量削峰
    • 在系统高峰期,通过RocketMQ缓存请求,避免因瞬时流量过大导致系统崩溃。
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 PeakShavingProducer {
    public static void main(String[] args) throws Exception {
        DefaultMQProducer producer = new DefaultMQProducer("PeakShavingProducerGroup");
        producer.setNamesrvAddr("127.0.0.1:9876");
        producer.start();

        Message msg = new Message("ShavingTopic", // topic
                "ShavingTag", // tag
                "ShavingKey123", // key
                ("Peak shaving request").getBytes(RemotingHelper.DEFAULT_CHARSET)); // body
        SendResult sendResult = producer.send(msg);
        System.out.printf("Peak shaving sent: %s%n", sendResult);

        producer.shutdown();
    }
}
  1. 数据同步
    • RocketMQ可以帮助实现数据的异步同步,保证数据一致性。
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 DataSyncProducer {
    public static void main(String[] args) throws Exception {
        DefaultMQProducer producer = new DefaultMQProducer("DataSyncProducerGroup");
        producer.setNamesrvAddr("127.0.0.1:9876");
        producer.start();

        Message msg = new Message("SyncTopic", // topic
                "SyncTag", // tag
                "SyncKey123", // key
                ("Data sync request").getBytes(RemotingHelper.DEFAULT_CHARSET)); // body
        SendResult sendResult = producer.send(msg);
        System.out.printf("Data sync sent: %s%n", sendResult);

        producer.shutdown();
    }
}
  1. 异步处理
    • 使用RocketMQ异步处理请求,可以显著提高系统响应速度和吞吐量。
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 AsyncRequestProducer {
    public static void main(String[] args) throws Exception {
        DefaultMQProducer producer = new DefaultMQProducer("AsyncProducerGroup");
        producer.setNamesrvAddr("127.0.0.1:9876");
        producer.start();

        Message msg = new Message("AsyncTopic", // topic
                "AsyncTag", // tag
                "AsyncKey123", // key
                ("Async request").getBytes(RemotingHelper.DEFAULT_CHARSET)); // body
        SendResult sendResult = producer.send(msg);
        System.out.printf("Async request sent: %s%n", sendResult);

        producer.shutdown();
    }
}

如何优化消息传递

  1. 消息压缩
    • 通过压缩消息体,减少网络传输时间。
  2. 批量发送
    • 多条消息合并发送,减少网络请求次数。
  3. 消息过滤
    • 在消息消费端增加消息过滤逻辑,减少不必要的消息处理。
深入理解RocketMQ架构

RocketMQ的基本架构

RocketMQ架构主要分为消息发送端、消息接收端、消息中间件(RocketMQ服务器)。

  1. 消息发送端
    • 负责将消息发送到RocketMQ服务器。
  2. 消息接收端
    • 负责从RocketMQ服务器拉取消息并进行消费。
  3. RocketMQ服务器
    • 名字服务(Name Server):负责维护Topic信息。
    • 消息服务(Broker):负责存储和转发消息。
    • 客户端(Producer和Consumer):负责发送和接收消息。

名字服务与消息服务详解

  1. 名字服务(Name Server)
    • 维护所有的Broker信息,并提供Broker的地址信息。
    • 主要功能是提供Topic到Broker的路由信息。
  2. 消息服务(Broker)
    • 负责存储消息。
    • 负责转发消息到客户端。
    • 实现消息的持久化、过滤、重试等机制。

高可用与可扩展性设计

  1. 高可用性
    • NameServer集群化部署,保证服务的高可用性。
    • Broker也可以配置集群,实现主备切换机制。
  2. 可扩展性
    • 通过增加NameServer和Broker节点,提高系统吞吐量。
    • 实现消息路由策略,提高系统的灵活性和适应性。
手写RocketMQ代码示例

编写发送消息的代码

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 Producer {
    public static void main(String[] args) throws Exception {
        DefaultMQProducer producer = new DefaultMQProducer("ProducerGroup");
        producer.setNamesrvAddr("127.0.0.1:9876");
        producer.start();

        Message msg = new Message("TestTopic", // topic
                "TagA", // tag
                "OrderID188", // key
                ("Hello RocketMQ.").getBytes(RemotingHelper.DEFAULT_CHARSET));

        SendResult sendResult = producer.send(msg);
        System.out.printf("SendResult: %s%n", sendResult);

        producer.shutdown();
    }
}

编写接收消息的代码

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

import java.util.List;

public class Consumer {
    public static void main(String[] args) throws Exception {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroup");
        consumer.setNamesrvAddr("127.0.0.1:9876");
        consumer.subscribe("TestTopic", "TagA");

        consumer.registerMessageListener((List<MessageExt> msgs, ConsumeOrderlyContext context) -> {
            for (MessageExt msg : msgs) {
                System.out.printf("Received message: %s%n", new String(msg.getBody()));
            }
            return ConsumeOrderlyStatus.SUCCESS;
        });

        consumer.start();
        System.out.println("Consumer started.");
    }
}

扩展功能代码示例

消息过滤示例

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext;
import org.apache.rocketmq.common.message.MessageExt;

import java.util.List;

public class ConsumerWithFilter {
    public static void main(String[] args) throws Exception {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroup");
        consumer.setNamesrvAddr("127.0.0.1:9876");
        consumer.subscribe("TestTopic", "*");

        consumer.registerMessageListener((List<MessageExt> msgs, ConsumeOrderlyContext context) -> {
            for (MessageExt msg : msgs) {
                String tag = msg.getTopic() + ":" + msg.getTag();
                if (tag.equals("TestTopic:TagA")) {
                    System.out.printf("Received message: %s%n", new String(msg.getBody()));
                } else {
                    System.out.println("Message filtered out.");
                }
            }
            return ConsumeOrderlyStatus.SUCCESS;
        });

        consumer.start();
        System.out.println("Consumer started with message filtering.");
    }
}

批量发送消息示例

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

public class ProducerWithBatch {
    public static void main(String[] args) throws Exception {
        DefaultMQProducer producer = new DefaultMQProducer("ProducerGroup");
        producer.setNamesrvAddr("127.0.0.1:9876");
        producer.start();

        Message[] msgs = new Message[10];
        for (int i = 0; i < 10; i++) {
            msgs[i] = new Message("TestTopic", // topic
                    "TagA", // tag
                    "OrderID" + i, // key
                    ("Hello RocketMQ batch " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
        }

        SendResult sendResult = producer.send(msgs);
        System.out.printf("SendResult: %s%n", sendResult);

        producer.shutdown();
    }
}

通过以上示例代码,可以详细了解RocketMQ的基本使用方式以及扩展功能的实现。

点击查看更多内容
TA 点赞

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

评论

作者其他优质文章

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

100积分直接送

付费专栏免费学

大额优惠券免费领

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

举报

0/150
提交
取消