前面的章节,我们已经把RocketMQ的环境搭建起来了,是一个两主两从的异步集群。接下来,我们就看看怎么去使用RocketMQ,在使用之前,先要在NameServer中创建Topic,我们知道RocketMQ是基于Topic的消息队列,在生产者发送消息的时候,要指定消息的Topic,这个Topic的路由规则是怎样的,这些都要在NameServer中去创建。

Topic的创建

我们先看看Topic的命令是如何使用的,如下:

./bin/mqadmin updateTopic -h

usage: mqadmin updateTopic -b <arg> | -c <arg>  [-h] [-n <arg>] [-o <arg>] [-p <arg>] [-r <arg>] [-s <arg>] -t
<arg> [-u <arg>] [-w <arg>]
-b,--brokerAddr <arg> create topic to which broker
-c,--clusterName <arg> create topic to which cluster
-h,--help Print help
-n,--namesrvAddr <arg> Name server address list, eg: 192.168.0.1:9876;192.168.0.2:9876
-o,--order <arg> set topic's order(true|false)
-p,--perm <arg> set topic's permission(2|4|6), intro[2:W 4:R; 6:RW]
-r,--readQueueNums <arg> set read queue nums
-s,--hasUnitSub <arg> has unit sub (true|false)
-t,--topic <arg> topic name
-u,--unit <arg> is unit topic (true|false)
-w,--writeQueueNums <arg> set write queue nums

其中有一段,-b <arg> | -c <arg>,说明这个Topic可以指定集群,也可以指定队列,我们先创建一个Topic指定集群,因为集群中有两个队列broker-abroker-b,看看我们的消息是否在两个队列中负载;然后再创建一个Topic指向broker-a,再看看这个Topic的消息是不是只在broker-a中。

创建两个Topic,

./bin/mqadmin updateTopic -c 'RocketMQ-Cluster' -t cluster-topic -n '192.168.73.130:9876;192.168.73.131:9876;192.168.73.132:9876'

./bin/mqadmin updateTopic -b 192.168.73.130:10911 -t broker-a-topic

第一个命令创建了一个集群的Topic,叫做cluster-topic;第二个命令创建了一个只在broker-a中才有的Topic,我们指定了-b 192.168.73.130:10911,这个是broker-a的地址和端口。

生产者发送消息

我们新建SpringBoot项目,然后引入RocketMQ的jar包,

<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.3.0</version>
</dependency>

然后配置一下生产者的客户端,在这里使用@Configuration这个注解,具体如下:

@Configuration
public class RocketMQConfig { @Bean(initMethod = "start",destroyMethod = "shutdown")
public DefaultMQProducer producer() {
DefaultMQProducer producer = new
DefaultMQProducer("DefaultMQProducer");
producer.setNamesrvAddr("192.168.73.130:9876;192.168.73.131:9876;192.168.73.132:9876;");
return producer;
}
}
  • 首先创建一个生产者组,名字叫做DefaultMQProducer;
  • 然后指定NameServer,192.168.73.130:9876;192.168.73.131:9876;192.168.73.132:9876;
  • 最后在@Bean注解中指定初始化的方法,和销毁的方法;

这样,生产者的客户端就配置好了,然后再写个Test类,在Test类中向MQ中发送消息,如下,

@SpringBootTest
class RocketmqDemoApplicationTests { @Autowired
public DefaultMQProducer defaultMQProducer; @Test
public void producerTest() throws Exception { for (int i = 0;i<5;i++) {
Message message = new Message();
message.setTopic("cluster-topic");
message.setKeys("key-"+i);
message.setBody(("this is simpleMQ,my NO is "+i).getBytes()); SendResult sendResult = defaultMQProducer.send(message);
System.out.println("SendStatus:" + sendResult.getSendStatus());
System.out.println("BrokerName:" + sendResult.getMessageQueue().getBrokerName());
}
}
}
  • 我们先自动注入前面配置DefaultMQProducer;
  • 然后在Test方法中,循环5次,发送5个消息,消息的Topic指定为cluster-topic,是集群的消息,然后再设置消息的key和内容,最后调用send方法发送消息,这个send方法是同步方法,程序运行到这里会阻塞,等待返回的结果;
  • 最后,我们打印出返回的结果和broker的名字;

运行一下,看看结果:

SendStatus:SEND_OK
BrokerName:broker-b
SendStatus:SEND_OK
BrokerName:broker-b
SendStatus:SEND_OK
BrokerName:broker-b
SendStatus:SEND_OK
BrokerName:broker-b
SendStatus:SEND_OK
BrokerName:broker-a

5个消息发送都是成功的,而发送的队列有4个是broker-b,1个broker-a,说明两个broker之间还是有负载的,负载的规则我们猜测是随机。

我们再写个测试方法,看看broker-a-topic这个Topic的发送结果是什么样子的,如下:

@Test
public void brokerTopicTest() throws Exception { for (int i = 0;i<5;i++) {
Message message = new Message();
message.setTopic("broker-a-topic");
message.setKeys("key-"+i);
message.setBody(("this is broker-a-topic's MQ,my NO is "+i).getBytes()); defaultMQProducer.send(message, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
System.out.println("SendStatus:" + sendResult.getSendStatus());
System.out.println("BrokerName:" + sendResult.getMessageQueue().getBrokerName());
} @Override
public void onException(Throwable e) {
e.printStackTrace();
}
}); System.out.println("异步发送 i="+i); }
}
  • 消息的Topic指定的是broker-a-topic,这个Topic我们只指定了broker-a这个队列;
  • 发送的时候我们使用的是异步发送,程序到这里不会阻塞,而是继续向下执行,发送的结果正常或者异常,会调用对应的onSuccess和onException方法;
  • 我们在onSuccess方法中,打印出发送的结果和队列的名称;

运行一下,看看结果:

异步发送 i=0

异步发送 i=1

异步发送 i=2

异步发送 i=3

异步发送 i=4

SendStatus:SEND_OK

SendStatus:SEND_OK

SendStatus:SEND_OK

SendStatus:SEND_OK

BrokerName:broker-a

SendStatus:SEND_OK

BrokerName:broker-a

BrokerName:broker-a

BrokerName:broker-a

BrokerName:broker-a

由于我们是异步发送,所以最后的日志先打印了出来,然后打印出返回的结果,都是发送成功的,并且队列都是broker-a,完全符合我们的预期。

消费者

生产的消息已经发送到了队列当中,再来看看消费者端如何消费这个消息,我们在这个配置类中配置消费者,如下:

@Bean(initMethod = "start",destroyMethod = "shutdown")
public DefaultMQPushConsumer pushConsumer() throws MQClientException {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("DefaultMQPushConsumer");
consumer.setNamesrvAddr("192.168.73.130:9876;192.168.73.131:9876;192.168.73.132:9876;");
consumer.subscribe("cluster-topic","*");
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
if (msgs!=null&&msgs.size()>0) {
for (MessageExt msg : msgs) {
System.out.println(new String(msg.getBody()));
System.out.println(context.getMessageQueue().getBrokerName());
}
} return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
} );
return consumer;
}
  • 我们创建了一个消费者组,名字叫做DefaultMQPushConsumer;
  • 然后指定NameServer集群,192.168.73.130:9876;192.168.73.131:9876;192.168.73.132:9876;
  • 消费者订阅的Topic,这里我们订阅的是cluster-topic,后面的*号是对应的tag,代表我们订阅所有的tag;
  • 最后注册一个并发执行的消息监听器,实现里边的consumeMessage方法,在方法中,我们打印出消息体的内容,和消息所在的队列;
  • 如果消息消费成功,返回CONSUME_SUCCESS,如果出现异常等情况,我们要返回RECONSUME_LATER,说明这个消息还要再次消费;

好了,这个订阅了cluster-topic的消费者,配置完了,我们启动一下项目,看看消费的结果如何,

this is simpleMQ,my NO is 2
broker-b
this is simpleMQ,my NO is 3
broker-b
this is simpleMQ,my NO is 1
broker-b
this is simpleMQ,my NO is 0
broker-a
this is simpleMQ,my NO is 4
broker-b

结果符合预期,cluster-topic中的5个消息全部消费成功,而且队列是4个broker-b,1个broker-a,和发送时的结果是一致的。

大家有问题欢迎评论区讨论~

RocketMQ系列(三)消息的生产与消费的更多相关文章

  1. ActiveMQ使用线程池实现消息的生产与消费

    jar文件:spring3.1jar,以及 项目src路径下文件:config.properties 读取config.properties文件JAVA类: package com.lejob.lej ...

  2. Redis系列(三)--消息队列、排行榜等

    Redis命令执行生命周期: 发送命令--->排队(单线程)--->执行命令--->返回结果 慢查询: 只是针对命令执行阶段 慢查询日志通过一个固定长度的FIFO queue,这个q ...

  3. JAVA代码之RocketMQ生产和消费数据

    一.启动RocketMQ [root@master ~]# cat /etc/hosts # Do not remove the following line, or various programs ...

  4. RocketMQ(消息重发、重复消费、事务、消息模式)

    分布式开放消息系统(RocketMQ)的原理与实践 RocketMQ基础:https://github.com/apache/rocketmq/tree/rocketmq-all-4.5.1/docs ...

  5. 消息中间件系列三:使用RabbitMq原生Java客户端进行消息通信(消费者(接收方)自动确认模式、消费者(接收方)自行确认模式、生产者(发送方)确认模式)

    准备工作: 1)安装RabbitMQ,参考文章:消息中间件系列二:RabbitMQ入门(基本概念.RabbitMQ的安装和运行) 2.)分别新建名为OriginalRabbitMQProducer和O ...

  6. Storm系列三: Storm消息可靠性保障

    Storm系列三: Storm消息可靠性保障 在上一篇 Storm系列二: Storm拓扑设计 中我们已经设计了一个稍微复杂一点的拓扑. 而本篇就是在上一篇的基础上再做出一定的调整. 在这里先大概提一 ...

  7. SpringBoot 整合 RabbitMQ(包含三种消息确认机制以及消费端限流)

    目录 说明 生产端 消费端 说明 本文 SpringBoot 与 RabbitMQ 进行整合的时候,包含了三种消息的确认模式,如果查询详细的确认模式设置,请阅读:RabbitMQ的三种消息确认模式 同 ...

  8. RocketMQ系列(四)顺序消费

    折腾了好长时间才写这篇文章,顺序消费,看上去挺好理解的,就是消费的时候按照队列中的顺序一个一个消费:而并发消费,则是消费者同时从队列中取消息,同时消费,没有先后顺序.RocketMQ也有这两种方式的实 ...

  9. RocketMQ系列(七)事务消息(数据库|最终一致性)

    终于到了今天了,终于要讲RocketMQ最牛X的功能了,那就是事务消息.为什么事务消息被吹的比较热呢?近几年微服务大行其道,整个系统被切成了多个服务,每个服务掌管着一个数据库.那么多个数据库之间的数据 ...

随机推荐

  1. spark机器学习从0到1特征抽取–Word2Vec(十四)

      一.概念 Word2vec是一个Estimator,它采用一系列代表文档的词语来训练word2vecmodel.该模型将每个词语映射到一个固定大小的向量.word2vecmodel使用文档中每个词 ...

  2. npm WARN enoent ENOENT: no such file or directory

    https://github.com/visionmedia/debug/issues/261

  3. 数据库范式1NF 2NF 3NF详细阐述

    范式:关系数据库中的关系是要满足一定要求的,满足不同程度要求的不同范式.满足最低要求的叫第一范式,简称1NF ,在第一范式中满足进一步要求的为第二范式,其余以此类推.通俗来说是满足数据库关系表中的一套 ...

  4. React面试题汇总

    1.如何理解React中的组件间数据传递? ①父-子  通过props传递 ②子-父  在父中创建一个可以修改state的方法,之后把这个方法通过props传递给子,在子中调用这个方法 从而达到修改父 ...

  5. 汉语拼音转换工具包pypinyin

    #pip install pypinyin汉字转换汉语拼音 from pypinyin import lazy_pinyin,TONE,TONE2,TONE3 str="你知道我是谁吗?&q ...

  6. kudu_遇到的一些问题

                            最近在研究,自己搭建kudu遇到的一些问题,及解决方法,供大家参考. 1.java连接kudu,出现超时的问题,是因为kudu开启了认证模式: 通过查找 ...

  7. Spring 自动装配 byType

    自动装配 byType,这种模式由属性类型指定自动装配. Spring 容器看作 beans,在 XML 配置文件中 beans 的 autowire 属性设置为 byType.然后,如果它的 typ ...

  8. Hibernate实现limit查询报错 :unexpected token: limit near line 1, column 33 [from pojo.Product p order by id limit ?,? ]

    原因: hibernate无法识别limit,  hql语句更不能这样写String hql="from Product p order by id limit ?,? "; 解决 ...

  9. Android_四大组件之ContentProvider

    一.概述 ContentProvider(内容提供者)管理对结构化数据集的访问,它们封装数据,并提供用于定义数据安全性的机制.其他应用,通过Context的ContentResolver对象 作为客户 ...

  10. C#线程 使用线程

    第三部分 使用线程 基于事件的异步模式 基于事件的异步模式(EAP)提供了一种简单的方法,通过这些方法,类可以提供多线程功能,而使用者无需显式启动或管理线程.它还提供以下功能: 合作取消模型 工作人员 ...