RocketMQ4.4安装使用总结

一、安装rocketmq(一主一从异步刷盘)

1、下载rocketmq

地址: https://www.apache.org/dyn/closer.cgi?path=rocketmq/4.4.0/rocketmq-all-4.4.0-source-release.zip 可以下载二进制文件,这样无需自己重新编译打包。

2、安装rocketmq

2.1、 安装java

2.1.1、下载jdk1.8

2.1.2、配置环境变量

export JAVA_HOME=/home/jdk1.8.0_191
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH

2.2、安装rocketmq (开始集群搭建)

执行命令unzip rocketmq-all-4.4.0-bin-release.zip解压文件。

配置环境变量:

#设置rocketmq环境变量
export ROCKETMQ_HOME=/home/rocketmq4.4
export PATH=${ROCKETMQ_HOME}/bin:$PATH

新建存储目录

mkdir -p /home/rocketmq4.4/data/store/{commitlog,consumequeue,index}

修改配置文件 (broker-a.properties)

[root@localhost 2m-2s-sync]# pwd
/home/rocketmq4.4/conf/2m-2s-sync
[root@localhost 2m-2s-sync]# 
[root@localhost 2m-2s-sync]# vim broker-a.properties
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#brokerClusterName=DefaultCluster
#brokerName=broker-a
#brokerId=0
#deleteWhen=04
#fileReservedTime=48
#brokerRole=SYNC_MASTER
#flushDiskType=ASYNC_FLUSH


#所属集群名称,如果多个master,那么每个master配置的名称应该一致,要不然识别不了
brokerClusterName=rocketmq-cluster
#broker名称
brokerName=broker-a
#0 表示master,>0 表示slave
brokerId=0
#nameServer地址,分号隔开
namesrvAddr=127.0.0.1:9876
#在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
defaultTopicQueueNums=4
#是否允许broker自动创建topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
#是否允许broker自动创建订阅组,建议线下开始,线上关闭
autoCreateSubscriptionGroup=true
#broker对外服务的监听端口,
#同一台机器部署多个broker,端口号要不同,且端口号之间要相距大些
listenPort=10911
#删除文件的时间节点,默认凌晨4点
deleteWhen=04
#文件保留时间,默认48小时
fileReservedTime=120
#commitLog每个文件的大小,默认大小1g
mapedFileSizeCommitLog=1073741824
#consumeQueue每个文件默认存30w条,根据自身业务进行调整
mapedFileSizeConsumeQueue=300000
destroyMapedFileInterval=120000
redeleteHangedFileInterval=120000
#检查物理文件磁盘空间
diskMaxUsedSpaceRatio=88
#store存储路径,master与slave目录要不同
storePathRootDir=/home/rocketmq4.4/data/store
#commitLog存储路径
storePathCommitLog=/home/rocketmq4.4/data/store/commitlog
#限制的消息大小
maxMessageSize=65536
flushCommitLogLeastPages=4
flushConsumeQueueLeastPages=2
flushCommitLogThoroughInterval=10000
flushConsumeQueueThoroughInterval=60000
checkTransactionMessageEnable=false
#发消息线程池数
sendMessageThreadPoolNums=128
#拉去消息线程池数
pullMessageThreadPoolNums=128
#broker角色:
#ASYSC_MASTER 异步复制master
#SYSC_MASTER 同步复制master
#SLAVE 从
brokerRole=SYSC_MASTER
#刷盘方式
#ASYNC_FLUSH 异步刷盘
#SYNC_FLUSH 同步刷盘
flushDiskType=ASYNC_FLUSH
brokerIP1=192.168.128.128

注意上处中的配置 brokerIP1 。 当本地的网络不止有一个ip地址的时候,容易出现连接不上的错误。会出现“ Caused by: org.apache.rocketmq.remoting.exception.RemotingConnectException: connect to 172.17.0.2:10911 failed 的问题”

据说这个问题的原因是因为虚拟机的多网卡造成的. 当使用命令 ifconfig 发现172.17.0.2 是docker的ip地址。当指定brikerIP1后,此问题解决。

修改配置文件(broker-a-s.properties)

# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#brokerClusterName=DefaultCluster
#brokerName=broker-a
#brokerId=1
#deleteWhen=04
#fileReservedTime=48
#brokerRole=SLAVE
#flushDiskType=ASYNC_FLUSH

brokerClusterName=rocketmq-cluster
brokerName=broker-a
brokerId=1
namesrvAddr=127.0.0.1:9876
defaultTopicQueueNums=4
autoCreateTopicEnable=true
autoCreateSubscriptionGroup=true
listenPort=10950
deleteWhen=04
fileReservedTime=120
mapedFileSizeCommitLog=1073741824
mapedFileSizeConsumeQueue=300000
destroyMapedFileInterval=120000
redeleteHangedFileInterval=120000
diskMaxUsedSpaceRatio=88
storePathRootDir=/home/rocketmq4.4/data/store/slave
storePathCommitLog=/home/rocketmq4.4/data/store/slave/commitlog
maxMessageSize=65536
flushCommitLogLeastPages=4
flushConsumeQueueLeastPages=2
flushCommitLogThoroughInterval=10000
flushConsumeQueueThoroughInterval=60000
checkTransactionMessageEnable=false
sendMessageThreadPoolNums=128
pullMessageThreadPoolNums=128
brokerRole=SLAVE
flushDiskType=ASYNC_FLUSH
brokerIP1=192.168.128.128

修改日志配置文件:

#创建日志目录
mkdir -p /home/rocketmq4.4/logs

#替换*.xml文件中的{user.home}为自己指定的目录
cd /home/rocketmq4.4/conf && sed -i 's#${user.home}#/home/rocketmq4.4#g' *.xml

改参数:

runbroker.sh,runserver.sh启动参数默认对jvm的堆内存设置比较大(不改启动不起来),如果是虚拟机非线上环境需要改下参数,大小可以根据自己机器来决定。

[root@localhost bin]# pwd
/home/rocketmq4.4/bin
[root@localhost bin]# ls
cachedog.sh         mqadmin      mqbroker.cmd        mqbroker.numanode3  mqnamesrv.xml   play.cmd       runbroker.sh   startfsrv.sh
cleancache.sh       mqadmin.cmd  mqbroker.numanode0  mqbroker.xml        mqshutdown      play.sh        runserver.cmd  tools.cmd
cleancache.v1.sh    mqadmin.xml  mqbroker.numanode1  mqnamesrv           mqshutdown.cmd  README.md      runserver.sh   tools.sh
hs_err_pid1551.log  mqbroker     mqbroker.numanode2  mqnamesrv.cmd       os.sh           runbroker.cmd  setcache.sh
[root@localhost bin]# 

在这里插入图片描述

runbroker.sh

JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m"
JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:SurvivorRatio=8"
JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:/dev/shm/mq_gc_%p.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy"
JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -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"
JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${BASE_DIR}/lib"
#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}"

runserver.sh

JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m"
JAVA_OPT="${JAVA_OPT} -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=8  -XX:-UseParNewGC"
JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:/dev/shm/rmq_srv_gc.log -XX:+PrintGCDetails"
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
JAVA_OPT="${JAVA_OPT}  -XX:-UseLargePages"
JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${BASE_DIR}/lib"
#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}"

如果还是出现内存问题,可尝试修改下面几个文件:

[root@node-100 bin]# pwd
/usr/local/rocketmq/rocketmq-4.2/bin
[root@node-100 bin]# ls *.xml
mqadmin.xml  mqbroker.xml  mqfiltersrv.xml  mqnamesrv.xml
[root@node-100 bin]# 

将这几个文件中下面参数给删掉:

-XX:PermSize	设置持久代(perm gen)初始值	物理内存的1/64	 
-XX:MaxPermSize	设置持久代最大值	物理内存的1/4

3、开始启动

先启动namesrv

[root@localhost bin]# cd /home/rocketmq4.4/bin
[root@localhost bin]#nohup sh mqnamesrv &
[root@localhost bin]# jps
2584 Jps
2553 NamesrvStartup

启动BrokerServer

[root@localhost bin] nohup sh mqbroker -c /home/rocketmq4.4/conf/2m-2s-async/broker-a.properties &

启动BrokerServer (slave)

[root@localhost bin] nohup sh mqbroker -c /home/rocketmq4.4/conf/2m-2s-async/broker-a-s.properties &

启动完成,查看集群信息

[root@localhost 2m-2s-async]# sh mqadmin clusterlist -n 127.0.0.1:9876
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=128m; support was removed in 8.0
#Cluster Name     #Broker Name            #BID  #Addr                  #Version                #InTPS(LOAD)       #OutTPS(LOAD) #PCWait(ms) #Hour #SPACE
rocketmq-cluster  broker-a                0     172.17.0.1:10911       V4_4_0                   0.00(0,0ms)         0.00(0,0ms)          0 430405.67 0.6731
rocketmq-cluster  broker-a                1     172.17.0.1:10950       V4_4_0                   0.00(0,0ms)         0.00(0,0ms)          0 430405.67 0.6731
[root@localhost 2m-2s-async]# 

启动成功!

二、RocketMQ Console搭建

RocketMQ有一个对其扩展的开源项目incubator-rocketmq-externals,这个项目中有一个子模块叫“rocketmq-console”,这个便是管理控制台项目了。

先将incubator-rocketmq-externals拉到本地,因为我们需要自己对rocketmq-console进行编译打包运行。
在这里插入图片描述

下载完成可以在下载路径看到有一个名为" rocketmq-externals "的文件夹,点进去可以看到rocketmq-console的子文件夹,这个呐,就是我们所需要的了~

进入该文件…\rocketmq-externals\rocketmq-console\src\main\resources\application.properties这个配置文件

在这里插入图片描述

标红线的地方是需要添加自己的NameServer地址,至于那个isVIPChannel设置为false,是因为开启VIP通道的话,端口就会改变,(连不上10911的问题,记得把防火墙把端口开放)

另外在rocketmq-console工程中的pom.xml中修改一下版本号(去除快照的版本号,默认是4.4.0-SNAPSHOT):此处困扰了好久,原来官方还有这个坑。。

在这里插入图片描述

修改好之后进行保存,打开Dos命令找到rocketmq-console的位置,对其进行编译打包成jar包

打包命令 mvn clean package -Dmaven.test.skip=true,我用mvn package一直报错,jar也生成不了。

之后会在该路径下生成一个jar文件

mvn clean package -f D:\opensource\rocketmq\rocketmq-console\rocketmq-externals\rocketmq-console\pom.xml  -Dmaven.test.skip=true

获取到jar文件后,执行

java -jar  rocketmq-console-ng-1.0.0.jar  启动控制台

三、java调用rocketmq
添加rocketmq的pom的依赖

<dependency>
	<groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-client</artifactId>
    <version>4.4.0</version>
</dependency>
  1. 同步发送消息:

原理:同步发送是指消息发送方发出数据后,会在收到接收方发回响应之后才发下一个数据包的通讯方式。

应用场景:此种方式应用场景非常广泛,例如重要通知邮件、报名短信通知、营销短信系统等。

public class SyncProducer {
    public static void main(String[] args) throws Exception {
        //Instantiate with a producer group name.
        //此处名字可以自己随便填写,rocketmq会自动创建;(我们在配置文件中有配置
        // #是否允许broker自动创建订阅组,建议线下开始,线上关闭
        // autoCreateSubscriptionGroup=true) 具体见broker-a.properties文件
        DefaultMQProducer producer = new
            DefaultMQProducer("rocketmq-cluster-SyncProducer");
        // Specify name server addresses.
        producer.setNamesrvAddr("localhost:9876");
        //Launch the instance.
        producer.start();
        for (int i = 0; i < 100; i++) {
            //Create a message instance, specifying topic, tag and message body.
            Message msg = new Message("TopicTest" /* Topic */,
                "TagA" /* Tag */,
                ("Hello RocketMQ " +
                    i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */
            );
            //Call send message to deliver message to one of brokers.
            SendResult sendResult = producer.send(msg);
            System.out.printf("%s%n", sendResult);
        }
        //Shut down once the producer instance is not longer in use.
        producer.shutdown();
    }
}
  1. 异步发送消息:

原理:异步发送是指发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。 消息队列 RocketMQ 的异步发送,需要用户实现异步发送回调接口(SendCallback)。消息发送方在发送了一条消息后,不需要等待服务器响应即可返回,进行第二条消息发送。发送方通过回调接口接收服务器响应,并对响应结果进行处理。

应用场景:异步发送一般用于链路耗时较长,对 RT 响应时间较为敏感的业务场景,例如用户视频上传后通知启动转码服务,转码完成后通知推送转码结果等。

public class AsyncProducer {
    public static void main(String[] args) throws Exception {
        //Instantiate with a producer group name.
        //此处名字可以自己随便填写,rocketmq会自动创建;(我们在配置文件中有配置
        // #是否允许broker自动创建订阅组,建议线下开始,线上关闭
        // autoCreateSubscriptionGroup=true) 具体见broker-a.properties文件
        DefaultMQProducer producer = new DefaultMQProducer("rocketmq-cluster-AsyncProducer");
        // Specify name server addresses.
        producer.setNamesrvAddr("localhost:9876");
        //Launch the instance.
        producer.start();
        producer.setRetryTimesWhenSendAsyncFailed(0);
        for (int i = 0; i < 100; i++) {
                final int index = i;
                //Create a message instance, specifying topic, tag and message body.
                Message msg = new Message("TopicTest",
                    "TagA",
                    "OrderID188",
                    "Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET));
                producer.send(msg, new SendCallback() {
                    @Override
                    public void onSuccess(SendResult sendResult) {
                        System.out.printf("%-10d OK %s %n", index,
                            sendResult.getMsgId());
                    }
                    @Override
                    public void onException(Throwable e) {
                        System.out.printf("%-10d Exception %s %n", index, e);
                        e.printStackTrace();
                    }
                });
        }
        //Shut down once the producer instance is not longer in use.
       // producer.shutdown();
        //注意此处要设置线程不退出,否则线程直接退出,就会发送消息失败。
        Thread.sleep(Long.MAX_VALUE);
    }
}

3.单项传输

原理:单向(Oneway)发送特点为发送方只负责发送消息,不等待服务器回应且没有回调函数触发,即只发送请求不等待应答。 此方式发送消息的过程耗时非常短,一般在微秒级别。

应用场景:适用于某些耗时非常短,但对可靠性要求并不高的场景,例如日志收集。

public class OnewayProducer {
    public static void main(String[] args) throws Exception{
        //Instantiate with a producer group name.
        DefaultMQProducer producer = new DefaultMQProducer("rocketmq-cluster");
        // Specify name server addresses.
        producer.setNamesrvAddr("192.168.128.128:9876");
        //Launch the instance.
        producer.start();
        for (int i = 0; i < 10; i++) {
            //Create a message instance, specifying topic, tag and message body.
            Message msg = new Message("TopicTest" /* Topic */,
                "TagA" /* Tag */,
                ("Hello RocketMQ " +
                    i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */
            );
            //Call send message to deliver message to one of brokers.
            producer.sendOneway(msg);

        }
        //Shut down once the producer instance is not longer in use.
        producer.shutdown();
    }
}

4.接收消息

public class Consumer {

    public static void main(String[] args) throws InterruptedException, MQClientException {
        //此处名字可以自己随便填写,rocketmq会自动创建;(我们在配置文件中有配置
        // #是否允许broker自动创建订阅组,建议线下开始,线上关闭
        // autoCreateSubscriptionGroup=true) 具体见broker-a.properties文件
        // Instantiate with specified consumer group name.
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("rocketmq-cluster");
         
        // Specify name server addresses.
        consumer.setNamesrvAddr("192.168.128.128:9876");
        
        // Subscribe one more more topics to consume.
        consumer.subscribe("TopicTest", "*");
        // Register callback to execute on arrival of messages fetched from brokers.
        consumer.registerMessageListener(new MessageListenerConcurrently() {

            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
                                                            ConsumeConcurrentlyContext context) {
                System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);

                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });

        //Launch the consumer instance.
        consumer.start();

        System.out.printf("Consumer Started.%n");

        Thread.sleep(Long.MAX_VALUE);

    }
}

5、多播模式 (consumer.setMessageModel(MessageModel.BROADCASTING);)

public class BroadcastConsumer {
    public static void main(String[] args) throws Exception {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("example_group_name");

        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);

        //set to broadcast mode
        consumer.setMessageModel(MessageModel.BROADCASTING);

        consumer.subscribe("TopicTest", "TagA || TagC || TagD");

        consumer.registerMessageListener(new MessageListenerConcurrently() {

            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
                ConsumeConcurrentlyContext context) {
                System.out.printf(Thread.currentThread().getName() + " Receive New Messages: " + msgs + "%n");
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });

        consumer.start();
        System.out.printf("Broadcast Consumer Started.%n");
    }
}
  1. 顺序消息

消息有序指的是可以按照消息的发送顺序来消费。

RocketMQ可以严格的保证消息有序。但这个顺序,不是全局顺序,只是分区(queue)顺序。要全局顺序只能一个分区。

下面是官方的一个例子

public class OrderedProducer {
    public static void main(String[] args) throws Exception {
        //Instantiate with a producer group name.
        MQProducer producer = new DefaultMQProducer("example_group_name");
        //Launch the instance.
        producer.start();
        String[] tags = new String[] {"TagA", "TagB", "TagC", "TagD", "TagE"};
        for (int i = 0; i < 100; i++) {
            int orderId = i % 10;
            //Create a message instance, specifying topic, tag and message body.
            Message msg = new Message("TopicTestjjj", tags[i % tags.length], "KEY" + i,
                    ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
            SendResult sendResult = producer.send(msg, new MessageQueueSelector() {
            @Override
            public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
                Integer id = (Integer) arg;
                int index = id % mqs.size();
                return mqs.get(index);
            }
            }, orderId);

            System.out.printf("%s%n", sendResult);
        }
        //server shutdown
        producer.shutdown();
    }
}

消费(注意: 此处是MessageListenerOrderly)

public class OrderedConsumer {
    public static void main(String[] args) throws Exception {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("example_group_name");

        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);

        consumer.subscribe("TopicTest", "TagA || TagC || TagD");

        consumer.registerMessageListener(new MessageListenerOrderly() {

            AtomicLong consumeTimes = new AtomicLong(0);
            @Override
            public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs,
                                                       ConsumeOrderlyContext context) {
                context.setAutoCommit(false);
                System.out.printf(Thread.currentThread().getName() + " Receive New Messages: " + msgs + "%n");
                this.consumeTimes.incrementAndGet();
                if ((this.consumeTimes.get() % 2) == 0) {
                    return ConsumeOrderlyStatus.SUCCESS;
                } else if ((this.consumeTimes.get() % 3) == 0) {
                    return ConsumeOrderlyStatus.ROLLBACK;
                } else if ((this.consumeTimes.get() % 4) == 0) {
                    return ConsumeOrderlyStatus.COMMIT;
                } else if ((this.consumeTimes.get() % 5) == 0) {
                    context.setSuspendCurrentQueueTimeMillis(3000);
                    return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT;
                }
                return ConsumeOrderlyStatus.SUCCESS;

            }
        });

        consumer.start();

        System.out.printf("Consumer Started.%n");
    }
}

3、事务消息

事务消息生产者:TransactionProducer.java

public class TransactionProducer {
    public static void main(String[] args) throws MQClientException, InterruptedException {
        TransactionListener transactionListener = new TransactionListenerImpl();
        TransactionMQProducer producer = new TransactionMQProducer("transactionGroup1");
        ExecutorService executorService = new ThreadPoolExecutor(2, 5, 100, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2000), new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setName("client-transaction-msg-check-thread");
                return thread;
            }
        });
        producer.setNamesrvAddr("192.168.128.128:9876");
        producer.setExecutorService(executorService);
        producer.setTransactionListener(transactionListener);
        producer.start();

        String[] tags = new String[] {"TagA", "TagB", "TagC", "TagD", "TagE"};
 
        for (int i = 0; i < 10; i++) {
            try {
                Message msg =
                    new Message("TopicTest1234", tags[i % tags.length], "KEY" + i,
                        ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
                SendResult sendResult = producer.sendMessageInTransaction(msg, null);
                System.out.printf("%s%n", sendResult);

                Thread.sleep(10);
            } catch (MQClientException | UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }

        for (int i = 0; i < 100000; i++) {
            Thread.sleep(1000);
        }
        producer.shutdown();
    }
}

TransactionListenerImpl.java

public class TransactionListenerImpl implements TransactionListener {
       private AtomicInteger transactionIndex = new AtomicInteger(0);
   
       private ConcurrentHashMap<String, Integer> localTrans = new ConcurrentHashMap<>();
   //会优先执行该方法
       @Override
       public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
           int value = transactionIndex.getAndIncrement();
           int status = value % 3;
           localTrans.put(msg.getTransactionId(), status);
           return LocalTransactionState.UNKNOW;
       }
   //当返回是UNKNOW 的时候,此检查方法会被定时的调用。
       @Override
       public LocalTransactionState checkLocalTransaction(MessageExt msg) {
           Integer status = localTrans.get(msg.getTransactionId());
           if (null != status) {
               switch (status) {
                   case 0:
                       return LocalTransactionState.UNKNOW;
                   case 1:
                       return LocalTransactionState.COMMIT_MESSAGE;
                   case 2:
                       return LocalTransactionState.ROLLBACK_MESSAGE;
               }
           }
           return LocalTransactionState.COMMIT_MESSAGE;
       }
   }

消费者和其他的一致,只要保障Topic和nameserver地址配置对即可。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值