RocketMQwiki是一个分布式消息和流数据平台,具有低延迟、高性能、高可靠性、万亿级容量和灵活的可扩展性。RocketMQ是2012年阿里巴巴开源的第三代分布式消息中间件,2016年11月21日,阿里巴巴向Apache软件基金会捐赠了RocketMQ;第二年2月20日,Apache软件基金会宣布Apache RocketMQ成为顶级项目。

RocketMQ 出现的原因是由于旧有的 ActiveMQ 无法满足业务要求,因此开发的一个能够满足业务需求的消息中间件。RocketMQ 的优点有很多,比如:高性能、高可靠等,但是由于某些原因,RocketMQ 可能并不像别的 MQ 那么的对开发人员友好

安装

首先,在官网上下载对应的源代码文件或者二进制文件:https://dlcdn.apache.org/rocketmq/,建议直接下载二进制文件,如果有特别需要的话,也可以下载对应的源文件,然后使用 Maven 构建即可。

据我个人的使用情况来看,下载源文件可能不是一个明智的选择,尽管官方的文档给出的是只要 JDK 1.8 或者以上的版本就可以,但是我在构建的过程中发现 RocketMQ 严重依赖于 JDK 1.8 特有的 API,因此我个人建议直接下载已经构建好的 jar

下载完成或者构建完成之后,应该是可以看到以下几个文件夹的:

其中,benchmark 文件夹包括对于 RocketMQ 的性能测试脚本;bin 目录下包含了一些启动 RocketMQ 以及配置相关的一些脚本;conf 目录下包含了所有的配置文件;lib 目录下则包含了所有的构建好的 jar 文件

启动 NameServer

如果没有指定配置文件的话,那么默认就是本地的 9876 端口,需要自定义相关属性的话,可以在 conf 目录下创建一个 namesrv.properties 的文件,定义需要的内容:

# 将 namesrv 的监听端口改为 8848
listenPort=8848

然后再运行启动 NamerServer 的脚本,具体如下:

# 当前的工作目录位于 RocketMQ 的基本工作目录,-c 选项表示加载对应的配置文件
./bin/mqnamesrv -c conf/namesrv.properties

此时启动 NameServer 可能会有问题,这个可能是由于 JDK 的版本太高,但是由于 RocketMQ 的默认启动是通过 JDK 1.8 特有的一种方式来启动的,因此可能会出现类似于以下这样的问题:

这是由于自从 JDK 9 开始,-Djava.ext.dirs 这个选项已经被废弃了,因此出现了这样的问题

解决方式:

手动编辑 bin/runserver.sh 文件,将 -Djava.ext.dirs 这个启动选项给去掉,但是这样又会导致一个新的问题,由于 ext 的类加载级别是要一般的应用级类加载器级别要高,因此此时是没有办法加载到实际运行的主类的,此时将对应的 jar 加入到 JVM 启动时的类中即可解决这个问题。

最终 bin/runserver.sh 修改后如下所示:

# 省略一部分不太重要的内容

[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=$HOME/jdk/java
[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/usr/java
[ ! -e "$JAVA_HOME/bin/java" ] && error_exit "Please set the JAVA_HOME variable in your environment, We need java(x64)!" export JAVA_HOME
export JAVA="$JAVA_HOME/bin/java"
export BASE_DIR=$(dirname $0)/.. # 这里是一次性将 RocketMQ 中 lib/ 目录下需要的所有的 jar 都放入 JVM 中,这样就能够成功找到对应的启动主类了
export CLASSPATH=.:${BASE_DIR}/lib/*:${BASE_DIR}/conf:${CLASSPATH} # 中间一大段无需修改 choose_gc_log_directory
choose_gc_options
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages" # -Djava.ext.dirs 这个选项需要被废除,这里直接将其注释掉
#JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${BASE_DIR}/lib:${JAVA_HOME}/lib/ext"
#JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n"
JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
JAVA_OPT="${JAVA_OPT} -cp ${CLASSPATH}" # 添加 --classpath # 这里是真正启动 JVM 的地方
$JAVA ${JAVA_OPT} $@

现在,再执行启动选项,就可以成功运行 RocketMQ 的 NameServer 了,启动时看起来像下面这样:

创建 Broker

首先,创建一个自己的 Broker 配置文件,具体内容如下所示:

# Broker 对应的监听端口
listenPort=12345
# Broker 的节点名
brokerClusterName = DefaultCluster
# Broker 的名字
brokerName = broker-a
# Broker 的 id,0 表示主节点,非 0 表示 从节点
brokerId = 0
# 不是特别重要的属性,表示在什么时候执行删除的操作,这里 04 表示凌晨 4 点
deleteWhen = 04
# 文件的保留时间,这里定义为 48 小时
fileReservedTime = 48
# Broker 所属类型,SYNC_MASTER 表示同步主节点,ASYNC_MASTER 表示异步主节点,SLAVE 表示从节点
brokerRole = SYNC_MASTER
# 刷盘策略,只有两种刷盘策略:SYNC_FLUSH 同步刷盘和 ASYNC_FLUSH 异步刷盘(可能有数据丢失)
flushDiskType = SYNC_FLUSH

然后启动 Broker,在 RocketMQ 的安装目录下执行对应的脚本即可,具体如下所示:

# -c 表示加载对应的配置文件,-n 表示 broker 连接的 NameServer 地址,之前已经将端口改为了 8848
./bin/mqbroker -n 127.0.0.1:8848 -c conf/master-broker.properties

如果使用的是高版本的 JDK,那么不出意外的话, 执行上面的内容依旧是会出现问题的(吐槽一句:脚本内容着实有待完善)。将 ./bin/runserver.sh 按照下面的步骤进行修改:

  1. 首先,将 -Djava.ext.dir 这个选项去掉
  2. 然后移除一些已经废除的 GC 选项。如:+XX:PrintAdaptiveSizePolicy-XX:+PrintGCDateStamps
  3. 修改 GC 的日志打印选项
  4. 修改加载的 CLASSPATH

在我的电脑上,安装的 JDK 版本为 openJDK-11.02,最终修改后的 ./bin/runserver.sh 的内容如下所示:

# 省去一部分不太重要的内容

export JAVA_HOME
export JAVA="$JAVA_HOME/bin/java"
export BASE_DIR=$(dirname $0)/..
# 修改 CLASSPTH,使得能够加载对应的主类
export CLASSPATH=.:${BASE_DIR}/lib/*:${BASE_DIR}/conf:${CLASSPATH} # 省去一段不太重要的内容。。。 # 默认情况下会设置 最大堆大小为 8 GB,如果是在自己的电脑上,建议将这两个值设置地小一点,否则可能会导致机器崩溃
JAVA_OPT="${JAVA_OPT} -server -Xms2g -Xmx2g"
# 一堆 GC 相关的属性配置,G1 收集器(如果可用的话)是一个很好的选择
JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0" # 这部分是需要修改的地方,将 -Xloggc:改成-Xlog:gc: (JDK 11 上如此),然后再删除掉一些废弃的选项,最后如下所示
# JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:${GC_LOG_DIR}/rmq_broker_gc_%p_%t.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy"
JAVA_OPT="${JAVA_OPT} -verbose:gc -Xlog:gc:${GC_LOG_DIR}/rmq_broker_gc_%p_%t.log" # 这一行整个启动选项都被废弃了
# JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m" #JAVA_OPT="${JAVA_OPT} -XX:GCLogFileSize=30m"
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
JAVA_OPT="${JAVA_OPT} -XX:+AlwaysPreTouch"
JAVA_OPT="${JAVA_OPT} -XX:MaxDirectMemorySize=15g"
JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages -XX:-UseBiasedLocking" # 注意将 -Djava.ext.dirs 这个启动选项去掉
#JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${BASE_DIR}/lib:${JAVA_HOME}/lib/ext"
#JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n"
JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
JAVA_OPT="${JAVA_OPT} -cp ${CLASSPATH}" # 省略一部分不太重要的内容

现在,再次启动自定义的 Broker,启动成功的结果会类似下图:

生产者发送消息

在发送和接受消息之前,需要添加 RocketMQ 对应的客户端依赖项:

<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.9.2</version> <!-- 对应具体的 RocketMQ 的版本 -->
</dependency>
  • 以同步阻塞的方式发送消息

    mport org.apache.rocketmq.client.producer.DefaultMQProducer;
    import org.apache.rocketmq.client.producer.SendResult;
    import org.apache.rocketmq.common.message.Message; import java.nio.charset.StandardCharsets;
    import java.util.Scanner; public class SyncProducer {
    public static void main(String[] args) throws Throwable {
    // 生产组为 lxh_producer
    DefaultMQProducer producer = new DefaultMQProducer("lxh_producer");
    // 设置 NameServer
    producer.setNamesrvAddr("127.0.0.1:9876");
    producer.start();
    Scanner sc = new Scanner(System.in);
    String line;
    // 读取客户端输入行,然后再发送
    while ((line = sc.nextLine()).length() > 0) {
    // 聚合成对ing的 Message
    Message msg = new Message(
    "TopicTest", // 发送消息到的目的 Topic,消费端可以按照这个进行消息的接收
    "TagA", // 该消息的 Tag,客户端可以对此进行过滤
    line.getBytes(StandardCharsets.UTF_8) // 将内容编码成字节流
    );
    // 以同步的方式发送消息,只有在消息发送完成之后才能进行后续的动作
    SendResult result = producer.send(msg);
    System.out.println(result);
    }
    producer.shutdown();
    }
    }
  • 以异步的方式发送消息

    package org.xhliu.rocketmqexample.producer;
    
    import org.apache.rocketmq.client.producer.DefaultMQProducer;
    import org.apache.rocketmq.client.producer.SendCallback;
    import org.apache.rocketmq.client.producer.SendResult;
    import org.apache.rocketmq.common.message.Message;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory; import java.nio.charset.StandardCharsets;
    import java.util.Scanner; public class AsyncProducer {
    static final Logger log = LoggerFactory.getLogger(AsyncProducer.class); public static void main(String[] args) throws Throwable {
    DefaultMQProducer producer = new DefaultMQProducer("lxh_producer");
    producer.setNamesrvAddr("127.0.0.1:8848");
    producer.start(); Scanner sc = new Scanner(System.in);
    String line;
    while ((line = sc.nextLine()).length() > 0) {
    Message msg = new Message(
    "TopicTest",
    "TagA",
    line.getBytes(StandardCharsets.UTF_8)
    ); // 以异步的方式发送消息,通过注册回调函数的方式来对返回结果进行处理
    producer.send(msg, new SendCallback() {
    @Override
    public void onSuccess(SendResult sendResult) {
    log.info("send result: " + sendResult.toString());
    } @Override
    public void onException(Throwable throwable) {
    log.error(throwable.getMessage());
    throwable.printStackTrace();
    }
    });
    } producer.shutdown();
    }
    }
  • 单向发送消息

    import org.apache.rocketmq.client.producer.DefaultMQProducer;
    import org.apache.rocketmq.common.message.Message;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory; import java.nio.charset.StandardCharsets; public class OneWayProducer {
    private final static Logger log = LoggerFactory.getLogger(OneWayProducer.class); public static void main(String[] args) throws Throwable{
    DefaultMQProducer producer = new DefaultMQProducer("lxh_producer");
    producer.setNamesrvAddr("127.0.0.1:8848");
    producer.start(); for (int i = 0; i < 10; i++) {
    // 创建消息,并指定Topic,Tag和消息体
    Message msg = new Message(
    "TopicTest" /* Topic */,
    "TagA" /* Tag */,
    ("Hello RocketMQ " + i).getBytes(StandardCharsets.UTF_8) /* Message body */
    );
    // 发送单向消息,没有任何返回结果
    producer.sendOneway(msg); }
    producer.shutdown();
    }
    }

消费者消费消息

消息的消费只能是阻塞的,具体的示例代码如下所示:

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.common.message.MessageExt; import java.nio.charset.StandardCharsets;
import java.util.List; public class SyncConsumer {
public static void main(String[] args) throws Throwable {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("lxh_consumer");
consumer.setNamesrvAddr("127.0.0.1:8848");
consumer.subscribe(
"TopicTest",
"*"
); consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(
List<MessageExt> list,
ConsumeConcurrentlyContext context
) {
for (MessageExt ext : list) {
System.out.println("Get Body: " + new String(ext.getBody(), StandardCharsets.UTF_8));
}
System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), list);
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
}); consumer.start();
System.out.println("Consumer Start.....");
}
}

参考:

[1] https://github.com/apache/rocketmq/blob/master/docs/cn/RocketMQ_Example.md

RocketMQ 的基本使用的更多相关文章

  1. RocketMQ原理解析-Remoting

    Remoting2. 通信层底层传输协议 RocketMq服务器与客户端通过传递RemotingCommand来交互,通过NettyDecoder,对RemotingCommand进行协议的编码与解码 ...

  2. RocketMQ原理解析-Broker

    broker 1. broker的启动 brker的启动 Broker向namesrv注册 1. 获取namesrv的地址列表(是乱序的) 2. 遍历向每个namesrv注册topic的配置信息top ...

  3. RocketMQ原理解析-Consumer

    consumer 1.启动 有别于其他消息中间件由broker做负载均衡并主动向consumer投递消息,RocketMq是基于拉模式拉取消息,consumer做负载均衡并通过长轮询向broker拉消 ...

  4. RocketMQ原理解析-Producer

    producer  producer 1.启动流程 Producer如何感知要发送消息的broker即brokerAddrTable中的值是怎么获得的, 1. 发送消息的时候指定会指定topic,如果 ...

  5. 分布式开放消息系统(RocketMQ)的原理与实践

    分布式消息系统作为实现分布式系统可扩展.可伸缩性的关键组件,需要具有高吞吐量.高可用等特点.而谈到消息系统的设计,就回避不了两个问题: 消息的顺序问题 消息的重复问题 RocketMQ作为阿里开源的一 ...

  6. rocketmq生产者和消费者

    1.生产者: package com.ebways.mq.test.mq; import com.alibaba.rocketmq.client.exception.MQClientException ...

  7. rocketmq查看命令

    首先进入 RocketMQ 工程,进入/RocketMQ/bin   在该目录下有个 mqadmin 脚本 .  查看帮助:   在 mqadmin 下可以查看有哪些命令    a: 查看具体命令的使 ...

  8. rocketmq生产者部署的机器注意事项

    报错: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'warningP ...

  9. Kafka vs RocketMQ——多Topic对性能稳定性的影响-转自阿里中间件

    引言 上期我们对比了RocketMQ和Kafka在多Topic场景下,收发消息的对比测试,RocketMQ表现稳定,而Kafka的TPS在64个Topic时可以保持13万,到了128个Topic就跌至 ...

  10. Kafka vs RocketMQ—— Topic数量对单机性能的影响-转自阿里中间件

    引言 上一期我们对比了三类消息产品(Kafka.RabbitMQ.RocketMQ)单纯发送小消息的性能,受到了程序猿们的广泛关注,其中大家对这种单纯的发送场景感到并不过瘾,因为没有任何一个网站的业务 ...

随机推荐

  1. 看完这篇HTTP,跟面试官扯皮就没问题了(转)

    认识 HTTP 首先你听的最多的应该就是 HTTP 是一种 超文本传输协议(Hypertext Transfer Protocol),这你一定能说出来,但是这样还不够,假如你是大厂面试官,这不可能是他 ...

  2. oracle clob字段信息读取,不限字符长度

    在项目中,经常需要在plsql中查询clob的内容,提供以下两种方法: 第一种,oracle常规函数,限制文本在4000以内 select dbms_lob.substr(sql_text) from ...

  3. How to parse OR AND within text

    假设你有一行 String condition = "A or B and C"; 语句,请问怎么做才能变成一行真正的逻辑表达式(能在计算机中运行计算)? Resolution 声 ...

  4. 甲骨文宣布: 也做 PostgreSQL!

    PostgreSQL 在开源数据库世界中一直是一个标志性的存在.经过35年的严格开发,它以其可靠性.强大的功能和性能而自豪.DB-engines 的突出显示,其市场份额的增长证明了其适应性强的数据模型 ...

  5. 树莓派3B/3B+的串口使用

    树莓派包含两个串口,一个称之为硬件串口(/dev/ttyAMA0),一个称之为mini串口(/dev/ttyS0).硬件串口由硬件实现,有单独的波特率时钟源,性能高.可靠.mini串口时钟源是由CPU ...

  6. TOP GP 把已经编译的per反编回对应版本的4fd(画面档)

    由于GP5.1,5.2,5.3的genero对应版本画面档开发互不兼容,下面提供各版本之间互转的操作方法: xshell切换到要反编译的per档目录,执行以下命令,就会在同目录下生成对应4fd档资料 ...

  7. Maximum Diameter 题解

    Maximum Diameter 题目大意 定义长度为 \(n\) 的序列 \(a\) 的权值为: 所有的 \(n\) 个点的第 \(i\) 个点的度数为 \(a_i\) 的树的直径最大值,如果不存在 ...

  8. Qt OpenGL textures详解

    1. 初始化opengl资源 Q_INIT_RESOURCE:textures(资源名称) QSurfaceFormat:定义3d面显示方式 如果在vs+qt vs tools 中无法正常显示3d图形 ...

  9. 从基础到实践,回顾Elasticsearch 向量检索发展史

    本文分享自华为云社区<Elasticsearch向量检索的演进与变革:从基础到应用>,作者: 汀丶. 1.引言 向量检索已经成为现代搜索和推荐系统的核心组件. 通过将复杂的对象(例如文本. ...

  10. 一文详解贝叶斯优化(Bayesian Optimization)原理

    参考资料: Expected Improvement formula for Bayesian Optimisation 通俗科普文:贝叶斯优化与SMBO.高斯过程回归.TPE 理解贝叶斯优化 A T ...