RocketMQ简介
- RocketMQ 是阿里巴巴开源的分布式消息中间件,2016 年捐赠给 Apache 软件基金会,2017 年毕业成为 Apache 顶级项目。它使用 Java 编写,天然对 Java 生态友好:客户端 API、序列化、线程模型对 Java 工程师几乎零学习成本,源码也便于排查问题。
- 4.x 是 RocketMQ 的经典架构版本:NameServer + Broker + Client 的扁平结构,没有任何第三方依赖(不需要 ZooKeeper),单机可支撑十万级 TPS。大量存量线上系统至今仍运行 4.x,理解它也是理解 5.x 的前提。
- 核心特性:
- 高吞吐、低延迟: 磁盘顺序写 + 内存映射(mmap)+ 页缓存(PageCache)+ 零拷贝,常态毫秒级投递延迟。
- 亿级消息堆积: 消息全部落盘、索引与数据分离,堆积不降低吞吐(消费不追热点数据时几乎无性能衰减)
- 功能完备: 事务消息、延时消息、顺序消息、消息轨迹、死信队列、消息查询(按 Key / 消息 ID)开箱即用。
- 部署极简: NameServer 无状态、节点间零通信,集群扩缩容只需增减进程。
- 客户端丰富: Java / C++ / Go / Python 等多语言客户端,Java 客户端最为成熟。
RocketMQ相关概念

-
RocketMQ架构上主要分为四部分:
-
Producer(消息生产者): 支持分布式集群方式部署。它会通过MQ的负载均衡模块选择相应的broker集群队列进行消息投递,投递的过程支持快速失败并且低延迟
-
Consumer(消息消费者): 支持分布式集群方式部署。存在pull、push两种消费模式消费消息,同时也支持集群方式和广播方式的消费。它提供实时消息订阅机制,可满足大多数场景需求
-
NameServer(路由注册中心): NameServer是一个简单的Topic路由注册中心,支持Broker的动态注册与发现。主要有两个功能:
- Broker管理:NameServer接收并保存Broker集群的注册信息,用于作为路由信息的基本数据(比如:Broker与Topic的映射关系),并提供心跳检测机制,检查Broker是否处于存活状态
- 路由信息管理:每个NameServer都会保存关于Broker集群的路由信息和用于客户端查询的队列信息
- 注意:NameServer通常使用集群方式部署,各实例间不进行信息通讯。Broker启动时会向集群中的每一台NameServer注册自己的路由信息(包含ip地址、端口号、topic等)。因此,当某一个NameServr宕机后,Broker仍可向其它NameServer同步其路由信息;Producer、Consumer仍可通过NameServer动态感知Broker的路由信息
-
BrokerServer: Broker主要负责消息的存储、投递、查询以及服务高可用保证,为了实现这些功能,Broker包含以下几个重要子模块:
- Remoting Module:整个Broker的实体,负责处理来自clients端的请求
- Client Manager:负责管理客户端(Producer/Consumer)并并维护Consumer的Topic订阅信息
- Store Service:提供方便简单的API接口用于查询或处理消息存储到磁盘
- HA Service:高可用服务,提供Master Broker和Slave Broker之间的数据同步功能
- Index Service:根据特定的Message key对投递到Broker的消息进行索引服务,以提供消息的快速查询

-
RocketMQ安装及启动
相关压缩包安装及配置
-
Step1: 进入RocketMQ官网下载(博主此处使用的是4.9.6版本)
RocketMQ官网有两个包:
- Source:java源码包,适合想读源码、调试源码、二次开发的人
- Binary:java源码编译后可运行的二进制包,用于部署RocketMQ
注意:博主此时均下载。Binary用于部署,Binary后期博主会来解读源码

-
Step2: 去jdk官网下载Linux版本的jdk1.8

-
Step3: 在Linux中利用下述命令分别创建java目录、rocketmq目录,然后将jdk的压缩包以及rocketmq的二进制包分别上传到对应的目录下
shmkdir -p /usr/local/java mkdir -p /usr/local/rocketmq -
Step4: 利用
cd /usr/local/java进入到java目录下,然后执行tar -zxvf jdk-8u202-linux-x64.tar.gz命令解压jdk包 -
Step5: 利用
cd /usr/local/rocketmq进入到rocketmq目录下,然后执行unzip rocketmq-all-4.9.6-bin-release.zip命令解压压缩包注意:若解压报错下述内容,则可通过
wget https://mirrors.aliyun.com/apache/rocketmq/4.9.6/rocketmq-all-4.9.6-bin-release.zip命令下载指定版本当当前目录下,然后在解压
-
Step6: 安装完成后在对应目录下分别使用下述命令删除对应的包
shrm -rf jdk-8u202-linux-x64.tar.gz rm -rf rocketmq-all-4.9.6-bin-release.zip -
Step7: 利用
vi /etc/profile命令进入对应文件,然后在文件末尾加上下述命令注意:profile是用来配置环境变量的文件
shexport JAVA_HOME=/usr/local/java/jdk1.8.0_202 export JRE_HOME=/usr/local/java/jdk1.8.0_202/jre export ROCKETMQ_HOME=/usr/local/rocketmq/rocketmq-all-4.9.6-bin-release export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$ROCKETMQ_HOME/bin:$PATH:$HOME/bin -
Step8: 执行
source /etc/profile命令使配置生效,然后使用java、javac两个命令验证配置是否生效
RocketMQ目录内容详解
-
rocketmq的conf目录下有五个重要内容(如下图所示),分别为:

- 2m-2s-async(双主双从 + 异步复制模板): Master 写完立即返回、Slave 后台同步(即使用异步方式进行主从之间的数据复制),性能高,吞吐量大,但Master 宕机瞬间可能丢失少量未同步消息
- 2m-2s-sync(双主双从 + 同步复制模板): Master 等 Slave 也落盘成功才返回(即使用同步方式进行主从之间的数据复制),能够保证消息安全投递,不会丢失,但写入延迟略高,影响吞吐量
- 2m-noslave(双主无从模板): 只有 Master 没有备份,性能最好、资源最省,
- 缺点:会存在单点故障,读的性能没有前两种好,任一Master节点宕机则宕机Master节点上的消息暂时不可消费
- dledger: 是基于 DLedger(Raft 协议)的多副本模板。由 Raft自动选主切主,解决传统主从架构 Master 宕机需人工切换的问题。
- 注意:dledger是第三方的插件,在RocketMQ4.5之后为实现高可用性引入的
- 解决的问题:2m-2s-async、2m-2s-sync、2m-noslave这三种官方提供的集群没办法实现高可用,在主节点宕机后并不会将某一个从节点升级为主节点(除非人工介入),而dledger就用来解决该问题
- broker.conf: 默认的单机 Broker 配置模板,不带集群拓扑
-
进入到2m-2s-async或2m-2s-sync目录下可看到两个主节点、两个从节点

单机部署
NameServer启动
-
Step1: 利用
vi /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/bin/runserver.sh命令进入到runserver文件中,更改nameServer所使用的JVM内存注意:RocketMQ默认的JVM内存为4G,由于博主是用来测试的,所以JVM内存配置小一点即可。若生产环境使用则根据实际情况配置大小

-
Step2: 利用下述命令静默启动nameServer
-n:说明启动的nameServer是在哪台服务器上的
shnohup /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/bin/mqnamesrv -n 192.168.204.128 & -
Step3: 启动完成后执行
cat nohup.out命令查看是否启动成功
Broker启动
-
Step1: 利用
vi /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/bin/runbroker.sh命令进入到broker文件中,更改broker所使用的JVM内存注意:由于博主是用来测试的,所以JVM内存配置小一点即可。若生产环境使用则根据实际情况配置大小

-
Step2: 利用
vi /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/conf/broker.conf进入broker.conf文件添加下述配置,开启自动创建topic功能shautoCreateTopicEnable=true -
Step3: 利用下述命令静默启动nameServer
-n:Broker启动时指定要注册到的NameServer的地址
shnohup /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/bin/mqbroker -n 192.168.204.128:9876 & -
Step4: 启动完成后执行
cat nohup.out命令查看是否启动成功
RocketMQ消息发送\消费验证
-
Step1: 利用
vi /etc/profile命令编辑profile文件,添加下述配置原因:在发送/接收消息之前,告知客户端NameServer的位置,让tools工具中的生产者和消费者程序读取该变量实现消息的生产和消费
shexport NAMESRV_ADDR=192.168.204.128:9876 -
Step2: 执行
source /etc/profile命令使配置生效 -
Step3: 使用bin/tools.sh工具验证生产者消息发送(默认会发送1000条消息),具体命令如下:
sh/usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/bin/tools.sh org.apache.rocketmq.example.quickstart.Producer
-
Step4: 使用bin/tools.sh工具验证生产者消息发送(默认会发送1000条消息),具体命令如下:
sh/usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer
RocketMQ关闭
-
依次利用下述命令关闭Broker、NameServer
sh/usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/bin/mqshutdown broker /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/bin/mqshutdown namesrv
集群部署
-
为了追求更好的性能,RocketMQ的最佳实践方式都是在集群模式下完成的。RocketMQ官方提供了三种集群搭建方式(具体可见 RocketMQ目录内容详解 这一部分内容):
-
2主2从异步通信方式
- 使用
conf/2m-2s-async文件夹内的配置文件做集群配置
- 使用
-
2主2从同步通信方式
- 使用
conf/2m-2s-sync文件夹内的配置文件做集群配置
- 使用
-
2主无从方式
- 使用conf/2m-noslave文件夹内的配置文件做集群配置
-
Dleger高可用集群
- 上述三种官方提供的集群没办法实现高可用时使用(即:在master节点宕机后,slave节点没办法自动被选举为新的master,必须借助人工实现选举)
-
搭建主从异步集群
在搭建主从异步集群前必须准备三台Linux服务器,三台Linux服务器中nameServer和broker之间的关系如下:
注意:
- 服务器2、3中分别创建了两个主节点,以及这两个主节点对应的从节点
- 同一主从节点不得在同一个服务器上
- 原因:若某一台服务器宕机,另一台服务器仍存在对应的相关节点,保持可用性
| 服务器 | 服务器IP | NameServer | broker节点部署 |
|---|---|---|---|
| 服务器1 | 192.168.204.128 | 192.168.204.128:9876 | |
| 服务器2 | 192.168.204.129 | 192.168.204.129:9876 | broker-a(master)、broker-b-s(slave) |
| 服务器3 | 192.168.204.130 | 192.168.204.130:9876 | broker-b(master)、broker-a-s(slave) |
-
Step1: 创建三台Linux服务器,创建完成后启动
- 注意:博主在进行单击部署时已有一台。因此,在创建两台即可。具体步骤可详见Linux(完整知识点汇总)这一部分内容

-
Step2: 依次在DemoTwo、DemoThree中按照
相关压缩包安装及配置这一小节执行一遍
NameServer启动
注意:该小节与 单机部署->NameServer启动 步骤一致,此处不再演示
服务器2的Broker启动
-
Step1: 在 服务器2 中利用
vi /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/conf/2m-2s-async/broker-a.properties命令编辑broker-a.properties配置文件,新增内容如下:主节点broker-a需要在broker-a.properties配置文件中配置
properties# 所属集群名称 brokerClusterName=DefaultCluster # broker名字 brokerName=broker-a # broker所在的服务器的ip(注意:需改为自己当前服务器的ip地址) brokerIP1=192.168.204.129 # broker的id,0代表master主节点,>0代表slave从节点 brokerId=0 # 删除文件时间点,默认在凌晨4点 deleteWhen=04 # 文件保留时间为48小时 fileReservedTime=48 # broker的角色为master(由于当前搭建的是异步集群,所以角色设置为ASYNC_MASTER) brokerRole=ASYNC_MASTER # 刷盘方式(由于当前是异步集群,所以配置为异步刷盘) flushDiskType=ASYNC_FLUSH # 名称服务器的地址列表namesrvAddr(即:NameServer集群IP地址) namesrvAddr=192.168.204.128:9876;192.168.204.129:9876;192.168.204.130:9876 # 在发送消息自动创建不存在的topic时,指定默认创建的队列数 defaultTopicQueueNums=4 # 是否允许Broker自动创建Topic(建议线下开启,线上关闭) autoCreateTopicEnable=true # 是否允许Broker自动创建订阅组,建议线下开启,线上关闭 autoCreateSubscriptionGroup=true # broker对外服务的监听端口(同一台服务器上多个 broker 端口不能冲突) listenPort=10911 # abort文件存储路径(注意:同一服务器上主节点和从节点的abort文件存储路径要分开,否则集群会启动失败) abortFile=/usr/local/rocketmq/store/abort # 消息存储路径(注意:同一服务器上主节点和从节点的消息存储路径要分开,否则集群会启动失败) storePathRootDir=/usr/local/rocketmq/store # commitLog存储路径(注意:同一服务器上主节点和从节点的commitLog存储路径要分开,否则集群会启动失败) storePathCommitLog=/usr/local/rocketmq/store/commitlog # 消息队列存储路径(注意:同一服务器上主节点和从节点的消息队列存储路径要分开,否则集群会启动失败) storePathConsumeQueue=/usr/local/rocketmq/store/consumequeue # 消息索引存储路径(注意:同一服务器上主节点和从节点的消息索引存储路径要分开,否则集群会启动失败) storePathIndex=/usr/local/rocketmq/store/index # checkpoint文件存储路径(注意:同一服务器上主节点和从节点的checkpoint文件存储路径要分开,否则集群会启动失败) storeCheckpoint=/usr/local/rocketmq/store/checkpoint # 限制的消息大小 maxMessageSize=65536 # commitLog每个文件的大小默认1G mapedFileSizeCommitLog=1073741824 # ConsumeQueue每个文件默认存30w条,根据业务情况调整 mapedFileSizeConsumeQueue=300000 -
Step2: 在 服务器2 中利用
vi /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/conf/2m-2s-async/broker-b-s.properties命令编辑broker-b-s.properties配置文件,新增内容如下:由于该从节点并不是当前服务器中broker-a主节点的从节点。因此,从节点需要在broker-b-s.properties配置文件中配置,而不是在broker-a-s.properties中配置
properties# 所属集群名称 brokerClusterName=DefaultCluster # broker名字 brokerName=broker-b # broker所在的服务器的ip(注意:需改为自己当前服务器的ip地址) brokerIP1=192.168.204.129 # broker的id,0代表master主节点,>0代表slave从节点 brokerId=1 # 删除文件时间点,默认在凌晨4点 deleteWhen=04 # 文件保留时间为48小时 fileReservedTime=48 # broker的角色为slave(由于当前搭建的是异步集群,所以角色设置为SLAVE) brokerRole=SLAVE # 刷盘方式(由于当前是异步集群,所以配置为异步刷盘) flushDiskType=ASYNC_FLUSH # 名称服务器的地址列表(即:NameServer集群IP地址) namesrvAddr=192.168.204.128:9876;192.168.204.129:9876;192.168.204.130:9876 # 在发送消息自动创建不存在的topic时,指定默认创建的队列数 defaultTopicQueueNums=4 # 是否允许Broker自动创建Topic(建议线下开启,线上关闭) autoCreateTopicEnable=true # 是否允许Broker自动创建订阅组,建议线下开启,线上关闭 autoCreateSubscriptionGroup=true # broker对外服务的监听端口(同一台服务器上多个 broker 端口不能冲突) listenPort=11011 # abort文件存储路径(注意:同一服务器上主节点和从节点的abort文件存储路径要分开,否则集群会启动失败) abortFile=/usr/local/rocketmq/store-slave/abort # 消息存储路径(注意:同一服务器上主节点和从节点的消息存储路径要分开,否则集群会启动失败) storePathRootDir=/usr/local/rocketmq/store-slave # commitLog存储路径(注意:同一服务器上主节点和从节点的commitLog存储路径要分开,否则集群会启动失败) storePathCommitLog=/usr/local/rocketmq/store-slave/commitlog # 消息队列存储路径(注意:同一服务器上主节点和从节点的消息队列存储路径要分开,否则集群会启动失败) storePathConsumeQueue=/usr/local/rocketmq/store-slave/consumequeue # 消息索引存储路径(注意:同一服务器上主节点和从节点的消息索引存储路径要分开,否则集群会启动失败) storePathIndex=/usr/local/rocketmq/store-slave/index # checkpoint文件存储路径(注意:同一服务器上主节点和从节点的checkpoint文件存储路径要分开,否则集群会启动失败) storeCheckpoint=/usr/local/rocketmq/store-slave/checkpoint # 限制的消息大小 maxMessageSize=65536 -
Step3: 利用
vi /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/bin/runbroker.sh命令进入到 服务器2 的broker文件中,更改broker所使用的JVM内存注意:由于博主是用来测试的,所以JVM内存配置小一点即可。若生产环境使用则根据实际情况配置大小

-
Step4: 利用下述命令依次静默启动两个broker
-c:指定对应的配置文件,使启动的集群满足配置内容
shnohup /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/bin/mqbroker -c /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/conf/2m-2s-async/broker-a.properties &shnohup /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/bin/mqbroker -c /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/conf/2m-2s-async/broker-b-s.properties &注意:博主图示方式中是将上述两个命令合并到一起来启动,实测会出问题导致只启动其中一个。因此,最好上述两个命令依次启动,并使用
cat nohup.out命令查看日志是否真正启动成功
-
Step5: 利用jps命令检查当前服务器是否存在两个broker,一个nameServer程序(目的:进一步验证是否启动成功)

服务器3的Broker启动
-
Step1: 在 服务器3 中利用
vi /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/conf/2m-2s-async/broker-b.properties命令编辑broker-a.properties配置文件,新增内容如下:主节点broker-b需要在broker-a.properties配置文件中配置
properties# 所属集群名称 brokerClusterName=DefaultCluster # broker名字 brokerName=broker-b # broker所在的服务器的ip(注意:需改为自己当前服务器的ip地址) brokerIP1=192.168.204.130 # broker的id,0代表master主节点,>0代表slave从节点 brokerId=0 # 删除文件时间点,默认在凌晨4点 deleteWhen=04 # 文件保留时间为48小时 fileReservedTime=48 # broker的角色为master(由于当前搭建的是异步集群,所以角色设置为ASYNC_MASTER) brokerRole=ASYNC_MASTER # 刷盘方式(由于当前是异步集群,所以配置为异步刷盘) flushDiskType=ASYNC_FLUSH # 名称服务器的地址列表(即:NameServer集群IP地址) namesrvAddr=192.168.204.128:9876;192.168.204.129:9876;192.168.204.130:9876 # 在发送消息自动创建不存在的topic时,指定默认创建的队列数 defaultTopicQueueNums=4 # 是否允许Broker自动创建Topic(建议线下开启,线上关闭) autoCreateTopicEnable=true # 是否允许Broker自动创建订阅组,建议线下开启,线上关闭 autoCreateSubscriptionGroup=true # broker对外服务的监听端口(同一台服务器上多个 broker 端口不能冲突) listenPort=10911 # abort文件存储路径(注意:同一服务器上主节点和从节点的abort文件存储路径要分开,否则集群会启动失败) abortFile=/usr/local/rocketmq/store/abort # 消息存储路径(注意:同一服务器上主节点和从节点的消息存储路径要分开,否则集群会启动失败) storePathRootDir=/usr/local/rocketmq/store # commitLog存储路径(注意:同一服务器上主节点和从节点的commitLog存储路径要分开,否则集群会启动失败) storePathCommitLog=/usr/local/rocketmq/store/commitlog # 消息队列存储路径(注意:同一服务器上主节点和从节点的消息队列存储路径要分开,否则集群会启动失败) storePathConsumeQueue=/usr/local/rocketmq/store/consumequeue # 消息索引存储路径(注意:同一服务器上主节点和从节点的消息索引存储路径要分开,否则集群会启动失败) storePathIndex=/usr/local/rocketmq/store/index # checkpoint文件存储路径(注意:同一服务器上主节点和从节点的checkpoint文件存储路径要分开,否则集群会启动失败) storeCheckpoint=/usr/local/rocketmq/store/checkpoint # 限制的消息大小 maxMessageSize=65536 # commitLog每个文件的大小默认1G mapedFileSizeCommitLog=1073741824 # ConsumeQueue每个文件默认存30w条,根据业务情况调整 mapedFileSizeConsumeQueue=300000 -
Step2: 在 服务器3 中利用
vi /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/conf/2m-2s-async/broker-a-s.properties命令编辑broker-a-s.properties配置文件,新增内容如下:由于该从节点并不是当前服务器中broker-b主节点的从节点。因此,从节点需要在broker-a-s.properties配置文件中配置,而不是在broker-b-s.properties中配置
注意:
- 同一服务器上不可能存在同一个broker的主从节点。因此,当前服务器上的broker节点(主/从)的对外服务的监听端口要与其它服务器上对应的broker节点(从/主)的监听端口要一致,否则无法搭建主从异步集群
properties# 所属集群名称 brokerClusterName=DefaultCluster # broker名字 brokerName=broker-a # broker所在的服务器的ip(注意:需改为自己当前服务器的ip地址) brokerIP1=192.168.204.130 # broker的id,0代表master主节点,>0代表slave从节点 brokerId=1 # 删除文件时间点,默认在凌晨4点 deleteWhen=04 # 文件保留时间为48小时 fileReservedTime=48 # broker的角色为slave(由于当前搭建的是异步集群,所以角色设置为SLAVE) brokerRole=SLAVE # 刷盘方式(由于当前是异步集群,所以配置为异步刷盘) flushDiskType=ASYNC_FLUSH # 名称服务器的地址列表(即:NameServer集群IP地址) namesrvAddr=192.168.204.128:9876;192.168.204.129:9876;192.168.204.130:9876 # 在发送消息自动创建不存在的topic时,指定默认创建的队列数 defaultTopicQueueNums=4 # 是否允许Broker自动创建Topic(建议线下开启,线上关闭) autoCreateTopicEnable=true # 是否允许Broker自动创建订阅组,建议线下开启,线上关闭 autoCreateSubscriptionGroup=true # broker对外服务的监听端口(同一台服务器上多个 broker 端口不能冲突) listenPort=11011 # abort文件存储路径(注意:同一服务器上主节点和从节点的abort文件存储路径要分开,否则集群会启动失败) abortFile=/usr/local/rocketmq/store-slave/abort # 消息存储路径(注意:同一服务器上主节点和从节点的消息存储路径要分开,否则集群会启动失败) storePathRootDir=/usr/local/rocketmq/store-slave # commitLog存储路径(注意:同一服务器上主节点和从节点的commitLog存储路径要分开,否则集群会启动失败) storePathCommitLog=/usr/local/rocketmq/store-slave/commitlog # 消息队列存储路径(注意:同一服务器上主节点和从节点的消息队列存储路径要分开,否则集群会启动失败) storePathConsumeQueue=/usr/local/rocketmq/store-slave/consumequeue # 消息索引存储路径(注意:同一服务器上主节点和从节点的消息索引存储路径要分开,否则集群会启动失败) storePathIndex=/usr/local/rocketmq/store-slave/index # checkpoint文件存储路径(注意:同一服务器上主节点和从节点的checkpoint文件存储路径要分开,否则集群会启动失败) storeCheckpoint=/usr/local/rocketmq/store-slave/checkpoint # 限制的消息大小 maxMessageSize=65536 -
Step3: 利用
vi /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/bin/runbroker.sh命令进入到 服务器3 的broker文件中,更改broker所使用的JVM内存注意:由于博主是用来测试的,所以JVM内存配置小一点即可。若生产环境使用则根据实际情况配置大小

-
Step4: 利用下述命令静默启动nameServer
-c:指定对应的配置文件,使启动的集群满足配置内容
shnohup /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/bin/mqbroker -c /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/conf/2m-2s-async/broker-b.properties &nohup /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/bin/mqbroker -c /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/conf/2m-2s-async/broker-a-s.properties &注意:博主图示方式中是将上述两个命令合并到一起来启动,实测会出问题导致只启动其中一个。因此,最好上述两个命令依次启动,并使用
cat nohup.out命令查看日志是否真正启动成功
-
Step5: 利用jps命令检查当前服务器是否存在两个broker,一个nameServer程序(目的:进一步验证是否启动成功)

服务器Broker配置类属性注意事项
| 属性 | 定义 | 注意 | 备注 |
|---|---|---|---|
brokerClusterName |
所属集群名称 | 同属一个集群的集群名称必须一致 | |
brokerName |
broker名称 | 同一broker的主从节点的broker名字必须一致 | |
| brokerId | broker的id | 0代表master主节点,>0代表slave从节点 | 集群中主从配对靠的是 brokerName 相同 + brokerId 区分 |
brokerRole |
broker的角色 | 角色名固定枚举,只有三个合法值:ASYNC_MASTER、SYNC_MASTER、SLAVE |
在RocketMQ5.x后新增合法值:ASYNC_SLAVE |
listenPort |
broker对外服务的监听端口 | 同一台服务器上多个 broker 端口不能冲突 | |
| namesrvAddr | 名称服务器的地址列表(即:NameServer集群IP地址) |
验证集群是否正常工作
为避免NameServe、Broker仅运行成功但不可正常工作。因此,使用RocketMQ集群提供的tools工具来验证集群是否可正常工作
-
Step1: 在服务器2上利用
vi /etc/profile命令编辑profile文件,添加下述配置原因:在发送/接收消息之前,告知客户端NameServer的位置,让tools工具中的生产者和消费者程序读取该变量实现消息的生产和消费
shexport NAMESRV_ADDR='192.168.204.128:9876;192.168.204.129:9876;192.168.204.130:9876' -
Step2: 执行
source /etc/profile命令使配置生效 -
Step3: 在服务器2使用bin/tools.sh工具验证生产者消息发送(默认会发送1000条消息),具体命令如下:
sh/usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/bin/tools.sh org.apache.rocketmq.example.quickstart.Producer -
Step3: 在服务器2使用bin/tools.sh工具验证生产者消息发送(默认会发送1000条消息),具体命令如下:
sh/usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer
注意:正常情况下可成功发送并消费消息。博主此处不再上传演示图
集群关闭
-
在对应服务器中依次利用下述命令关闭Broker、NameServer即可
sh/usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/bin/mqshutdown broker /usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/bin/mqshutdown namesrv
mqadmin管理工具
RocketMQ的bin目录下提供了命令工具用于管理topic、broker、集群、消息等。
mqadmin常见命令-创建topic
命令:updateTopic
示例:创建名为myTopic1的topic,且指定所属集群的名称为DefaultCluster
sh
/usr/local/rocketmq/rocketmq-all-4.9.6-bin-release/bin/mqadmin updateTopic -n 192.168.204.129:9876 -c DefaultCluster -t myTopic1

| 参数 | 是否必填 | 备注 |
|---|---|---|
| -b | 若-c为空,则该参数必填 | broker地址,表示topic建在该broker上(并不是集群中的每个broker都会创建指定topic) |
| -c | 若-b为空,则该参数必填 | cluster名称,表示topic建在该集群(即:集群中的每个broker上都有;集群可通过clusterList查询) |
| -h | 否 | 打印帮助 |
| -n | 是 | nameServer服务地址列表,格式:ip:port;ip:port |
| -p | 否 | 指定新topic的权限限制(W|R|WR) |
| -r | 否 | 可读队列数(默认为8) |
| -w | 否 | 可写队列数(默认为8) |
| -t | 是 | opic名称(名称只能使用字符^[a-zA-Z0-9_-+$) |
mqadmin常见命令-删除topic
命令deleteTopic
| 参数 | 是否必填 | 备注 |
|---|---|---|
| -c | 是 | cluster名称,表示删除某个集群下的某个topic(集群可通过clusterList查询) |
| -h | 否 | 打印帮助 |
| -n | 是 | nameServer服务地址列表,格式:ip:port;ip:port |
| -t | 是 | opic名称(名称只能使用字符^[a-zA-Z0-9_-+$) |
mqadmin常见命令-创建/修改订阅组
命令updateSubGroup
| 参数 | 是否必填 | 备注 |
|---|---|---|
| -b | 若-c为空,则该参数必填 | broker地址,表示订阅组建在该broker |
| -c | 若-b为空,则该参数必填 | cluster名称,表示topic建在该集群(集群可通过clusterList查询) |
| -d | 否 | 是否允许广播方式消费 |
| -g | 是 | 订阅组名 |
| -i | 否 | 从哪个broker开始消费 |
| -m | 否 | 是否容许从队列的最小位置开始消费,默认为false |
| -q | 否 | 消费失败的消息放到一个重试队列,每个订阅组配置几个重试队列 |
| -r | 否 | 重试消费的最大次数,超过则投递到死信队列,此时不投递并报警 |
| -s | 否 | 消费功能是否开启 |
| -w | 否 | 发现消息堆积后,将Consumer的消费请求重定向到另一台Slave机器 |
| -h | 否 | 打印帮助 |
| -n | 是 | nameServer服务地址列表,格式:ip:port;ip:port |
mqadmin常见命令-删除订阅组配置
命令deleteSubGroup
| 参数 | 是否必填 | 备注 |
|---|---|---|
| -b | 若-c为空,则该参数必填 | broker地址,表示订阅组建在该broker |
| -c | 若-b为空,则该参数必填 | cluster名称,表示topic建在该集群(集群可通过clusterList查询) |
| -g | 是 | 订阅组名 |
| -h | 否 | 打印帮助 |
| -n | 是 | nameServer服务地址列表,格式:ip:port;ip:port |
mqadmin常见命令-更新Broker配置文件
命令updateBrokerConfig
| 参数 | 是否必填 | 备注 |
|---|---|---|
| -b | 若-c为空,则该参数必填 | broker地址,表示订阅组建在该broker |
| -c | 若-b为空,则该参数必填 | cluster名称,表示topic建在该集群(集群可通过clusterList查询) |
| -k | 是 | key值 |
| -v | 否 | value值 |
| -h | 否 | 打印帮助 |
| -n | 是 | nameServer服务地址列表,格式:ip:port;ip:port |
mqadmin常见命令-查看topic列表信息
命令topicList
| 参数 | 是否必填 | 备注 |
|---|---|---|
| -h | 否 | 打印帮助 |
| -n | 是 | nameServer服务地址列表,格式:ip:port;ip:port |
mqadmin常见命令-查看topic路由信息
命令topicRoute
| 参数 | 是否必填 | 备注 |
|---|---|---|
| -t | 是 | topic名称 |
| -h | 否 | 打印帮助 |
| -n | 是 | nameServer服务地址列表,格式:ip:port;ip:port |
mqadmin常见命令-查看topic统计信息
命令topicStats
| 参数 | 是否必填 | 备注 |
|---|---|---|
| -t | 是 | topic名称 |
| -h | 否 | 打印帮助 |
| -n | 是 | nameServer服务地址列表,格式:ip:port;ip:port |
mqadmin常见命令-根据消息ID查询消息
命令queryMsgById
| 参数 | 是否必填 | 备注 |
|---|---|---|
| -i | 是 | 消息ID |
| -h | 否 | 打印帮助 |
| -n | 是 | nameServer服务地址列表,格式:ip:port;ip:port |
mqadmin常见命令-根据消息key查询消息
命令queryMsgByKey
| 参数 | 是否必填 | 备注 |
|---|---|---|
| -f | 否 | 被查询消息的截止时间 |
| -k | 是 | msgKey |
| -t | 是 | topic名称 |
| -h | 否 | 打印帮助 |
| -n | 是 | nameServer服务地址列表,格式:ip:port;ip:port |
mqadmin常见命令-根据Offset查询消息
命令queryMsgByOffset
| 参数 | 是否必填 | 备注 |
|---|---|---|
| -b | 是 | Broker名称,表示订阅组建在该Broker(注意:此处填写的是Broker名称,不是地址,broker名称可在clusterList查询) |
| -i | 是 | query队列id |
| -o | 是 | offset值 |
| -t | 是 | topic名称 |
| -h | 否 | 打印帮助 |
| -n | 是 | nameServer服务地址列表,格式:ip:port;ip:port |
mqadmin常见命令-查询Producer的网络连接
命令producerConnection
| 参数 | 是否必填 | 备注 |
|---|---|---|
| -g | 是 | 生产者所属组名 |
| -t | 是 | topic名称 |
| -h | 否 | 打印帮助 |
| -n | 是 | nameServer服务地址列表,格式:ip:port;ip:port |
mqadmin常见命令-查询Consumer的网络连接
命令consumerConnection
| 参数 | 是否必填 | 备注 |
|---|---|---|
| -g | 是 | 消费者所属组名 |
| -h | 否 | 打印帮助 |
| -n | 是 | nameServer服务地址列表,格式:ip:port;ip:port |
mqadmin常见命令-查询订阅组消费状态
命令consumerProgress
| 参数 | 是否必填 | 备注 |
|---|---|---|
| -g | 是 | 消费者所属组名 |
| -h | 否 | 打印帮助 |
| -n | 是 | nameServer服务地址列表,格式:ip:port;ip:port |
mqadmin常见命令-查看集群消息
命令clusterList
| 参数 | 是否必填 | 备注 |
|---|---|---|
| -m | 否 | 打印更多信息 |
| -h | 否 | 打印帮助 |
| -n | 是 | nameServer服务地址列表,格式:ip:port;ip:port |
可视化管理控制平台安装及使用
注意:博主将可视化管理控制平台安装到了服务器1上
前置步骤
可视化管理控制平台安装前需要保证Linux中已安装Jdk、Maven、已启动nameServer、Broker
由于博主除了Maven外,其余均已完成。因此,需要先安装Maven
-
Step1: 进入Maven官网下载对应版本的Maven(博主版本为3.9.16)

-
Step2: 在Linux中利用
mkdir -p /usr/local/maven命令创建maven目录,然后将maven的二进制包上传到该目录下 -
Step3: 利用
cd /usr/local/maven进入到maven目录下,然后执行tar -zxvf apache-maven-3.9.16-bin.tar.gz命令解压maven包 -
Step4: 利用
vi /etc/profile命令来配置maven环境变量,在profile文件中新增下述配置shexport MAVEN_HOME=/usr/local/maven/apache-maven-3.9.16 export PATH=$JAVA_HOME/bin:$MAVEN_HOME/bin:$PATH -
Step5: 执行
source /etc/profile命令使配置生效,然后使用mvn -v命令验证配置是否生效
可视化管理控制平台安装
注意:可视化管理控制平台安装也可去官方管理控制平台下载zip包将其解压到本地,然后用idea打开,修改完application.yml后打包生成jar包,并将jar包上传至Linux,通过
java -jar rocketmq-dashboard-2.0.0.jar命令运行。博主此处仅演示全程在Linux中是如何操作的,在windows平台利用idea的实现可自行尝试
-
Step1: 进入官方管理控制平台下载zip包
注意:
- 博主此处下载的是2.0.0版本
- 原因:2.0.0版本之后要求jdk版本在17及其以上,而本次案例中博主使用的是jdk1.8构建的RocketMQ
- 在实测过程中由于2.0.0版本中对应的ocketMQ依赖版本为5.1.0(博主使用的为RocketMQ4.9.6)。因此,在操作可视化管理控制平台过程中可能会无法操作甚至操作失败。
- 建议:为避免遇到与博主一样的问题。建议使用RocketMQ4.9.0版本,可视化管理控制平台使用1.0.0版本
- 原因:可视化管理控制平台1.0.0版本中使用的RocketMQ版本为4.9.0

- 博主此处下载的是2.0.0版本
-
Step2: 在Linux中利用
mkdir -p /usr/local/rocketmq/rocketmq-dashboard命令创建rocketmq-dashboard目录,然后将rocketmq-dashboard的压缩包上传到该目录下 -
Step3: 利用
cd /usr/local/rocketmq/rocketmq-dashboard进入到rocketmq-dashboard目录下,然后执行unzip rocketmq-dashboard-rocketmq-dashboard-2.0.0.zip命令解压rocketmq-dashboard包 -
Step4: 利用
vi /usr/local/rocketmq/rocketmq-dashboard/rocketmq-dashboard-rocketmq-dashboard-2.0.0/src/main/resources/application.yml命令在application.yml中更新rocketmq.config.namesrvAddrs配置的ip地址为当前集群中NameServer的ip地址
-
Step5: 利用
cd /usr/local/rocketmq/rocketmq-dashboard/rocketmq-dashboard-rocketmq-dashboard-2.0.0进入到rocketmq-dashboard项目目录下,双击打开pom文件(如图一所示),然后在pom文件中为yarn配置国内yarn源(如图二所示)
xml<configuration> <nodeVersion>v16.2.0</nodeVersion> <yarnVersion>v1.22.10</yarnVersion> <nodeDownloadRoot>https://cdn.npmmirror.com/binaries/node/</nodeDownloadRoot> <yarnDownloadRoot>https://repo.huaweicloud.com/yarn/</yarnDownloadRoot> </configuration> -
Step6: 利用
cd /usr/local/rocketmq/rocketmq-dashboard/rocketmq-dashboard-rocketmq-dashboard-2.0.0进入到rocketmq-dashboard项目目录下,然后利用mvn clean package -Dmaven.test.skip=true命令对该rocketmq-dashboard项目进行打包注意:打包完成后可看到target目录下有一个jar包(如图所示)

-
Step7: 利用
cd /usr/local/rocketmq/rocketmq-dashboard/rocketmq-dashboard-rocketmq-dashboard-2.0.0/target进入到target目录,然后利用java -jar rocketmq-dashboard-2.0.0.jar启动项目。如图所示即为启动成功
-
Step8: 在浏览器中输入
IP地址:8080即可访问可视化管理控制平台(如图所示)注意:博主在服务器1上安装的可视化管理控制平台。因为地址为:http://192.168.204.128:8080/

RocketMQ快速入门
示例:生产者向消息队列发送"HelloWorld!!!",然后由消费者从消息队列接收到消息并在控制台输出
注意:
- 微服务项目搭建此处不再演示,具体可详见SpringCloud项目搭建快速入门
- 本案例Demo已上传至Gitee,可详见Gitee项目RocketMQDemo分支-快速入门
前置步骤
-
在父pom文件中新增rocketmq-client依赖
注意:该依赖版本必须与RocketMQ部署的版本一致,博主部署时使用的是4.9.6。因此,rocketmq-client依赖依赖版本为4.9.6
xml<!--RocketMQ相关依赖--> <dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-client</artifactId> <version>4.9.6</version> </dependency>完整父pom文件如下:
xml<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>at.guigu</groupId> <artifactId>RocketMQDemo</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>consumer</module> <module>publisher</module> </modules> <properties> <maven.compiler.source>21</maven.compiler.source> <maven.compiler.target>21</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring-boot.version>3.0.7</spring-boot.version> <spring-cloud.version>2022.0.3</spring-cloud.version> <spring-cloud-alibaba.version>2022.0.0.0-RC2</spring-cloud-alibaba.version> <hutool-all.version>5.8.25</hutool-all.version> </properties> <!--5 配置公共依赖--> <dependencies> <!--启动类相关依赖:SpringBoot依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--RocketMQ相关依赖--> <dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-client</artifactId> <version>4.9.6</version> </dependency> <!--测试类相关依赖:spring-boot-starter-test--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--添加Junit单元测试依赖--> <dependency > <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> <!--lombok依赖--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!--hutool坐标--> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>${hutool-all.version}</version> </dependency> </dependencies> <!--6 配置可选依赖--> <dependencyManagement> <dependencies> <!-- 覆盖SpringBoot默认的lombok 1.18.26(不支持JDK 21编译),须在import之前声明才生效 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.36</version> </dependency> <!-- springboot的依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- springcloud依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!--spring-cloud-alibaba--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <!--7 配置插件--> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
生产者模块步骤
-
Step1: 在生产者模块(即publisher模块)中创建测试类
RocketMQPubTest,测试代码如下:javapackage at.guigu; import org.apache.rocketmq.client.producer.DefaultMQProducer; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.message.Message; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import java.nio.charset.StandardCharsets; @SpringBootTest public class RocketMQPubTest { @Test void pubTest() throws Exception { // Step1:创建生产者并指定生产者组 DefaultMQProducer producer = new DefaultMQProducer("my-producer-group1"); // Step2:指定nameServer地址(集群中任意一个nameServer的ip地址即可) producer.setNamesrvAddr("192.168.204.128:9876"); // Step3:启动生产者 producer.start(); for (int i = 0; i < 10; i++) { // Step4:消息创建---注意:Message所在包为org.apache.rocketmq.common.message.Message Message msg = new Message("MyTopic1", "TagA", ("HelloWorld!!! " + i).getBytes(StandardCharsets.UTF_8)); // Step5:(同步)消息发送 SendResult result = producer.send(msg); System.out.println(result); // 打印发送结果 } // Step6:关闭生产者 producer.shutdown(); } } -
Step2: 运行该测试类,可看到如图所示内容

-
Step3: 进入到 可视化管理控制平台->消息 界面,选择指定的Topic即可看到发送的10条消息

消费者模块步骤
-
Step1: 在生产者模块(即publisher模块)中创建可单独启动的消费者类
BaseConsumer,测试代码如下:注意:由于当前还未springboot整合rocketmq。因此,博主此处创建一个不依赖消费者模块启动类的消费者类来实现消费(即该类可单独执行,不用启动消费者模块启动类)
javapackage at.guigu.consumer; 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 BaseConsumer { public static void main(String[] args) throws MQClientException { // Step1:创建消费者并指定消费者组 DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("my-producer-group1"); // Step2:指定nameServer地址(集群中任意一个nameServer的ip地址即可) consumer.setNamesrvAddr("192.168.204.128:9876"); // Step3:消费者订阅对应的Topic,且过滤出tags为"TagA"的消息进行消费 // 注意:若消费当前订阅的topic下的所有消息,则参数二改为"*"即可 consumer.subscribe("MyTopic1", "TagA"); // Step4:创建一个消息监听器,当Broker将消息push过来时调用,以实现消息消费 consumer.registerMessageListener(new MessageListenerConcurrently() { /** * * @param msgs broker推过来的消息都在该列表中 * @param consumeConcurrentlyContext 上下文对象 * @return */ @Override public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext consumeConcurrentlyContext) { try { // 具体消费逻辑 msgs.forEach(msg -> { System.out.println("收到的消息:" + msg); }); } catch (Exception e) { // 若消费失败则返回RECONSUME_LATER,代表后续会重新消费 return ConsumeConcurrentlyStatus.RECONSUME_LATER; } // 若消费成功则返回CONSUME_SUCCESS return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; } }); // Step5:启动消费者 consumer.start(); System.out.println("consumer running..."); } } -
Step2: 启动消费者类
BaseConsumer,控制台输入如图所示:
由图可知,消息为字节码数组。因此,若想要获取消息内容则需解码字节码数组:
javapackage at.guigu.consumer; 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.nio.charset.StandardCharsets; import java.util.List; public class BaseConsumer { public static void main(String[] args) throws MQClientException { // Step1:创建消费者并指定消费者组 DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("my-producer-group1"); // Step2:指定nameServer地址(集群中任意一个nameServer的ip地址即可) consumer.setNamesrvAddr("192.168.204.128:9876"); // Step3:消费者订阅对应的Topic,且过滤出tags为"TagA"的消息进行消费 // 注意:若消费当前订阅的topic下的所有消息,则参数二改为"*"即可 consumer.subscribe("MyTopic1", "TagA"); // Step4:创建一个消息监听器,当Broker将消息push过来时调用,以实现消息消费 consumer.registerMessageListener(new MessageListenerConcurrently() { /** * * @param msgs broker推过来的消息都在该列表中 * @param consumeConcurrentlyContext 上下文对象 * @return */ @Override public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext consumeConcurrentlyContext) { try { // 具体消费逻辑 msgs.forEach(msg -> { // 将获取到的字节码数组解码后输出 System.out.println("收到的消息:" + new String(msg.getBody(), StandardCharsets.UTF_8)); }); } catch (Exception e) { // 若消费失败则返回RECONSUME_LATER,代表后续会重新消费 return ConsumeConcurrentlyStatus.RECONSUME_LATER; } // 若消费成功则返回CONSUME_SUCCESS return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; } }); // Step5:启动消费者 consumer.start(); System.out.println("consumer running..."); } }此时输出如下图所示:
