目录
前言
RocketMQ的由4部分组成:NameServers,Broker,Producer,Consumer
- NameServer是一个几乎无状态节点,可集群部署,节点之间无任何信息同步
- Broker具体存储topic、消息的组件,Broker分为Master与Slave,一个Master可以对应多个Slave,但是一个Slave只能对应一个Master,Master与Slave 的对应关系通过指定相同的BrokerName,不同的BrokerId 来定义,BrokerId为0表示Master,非0表示Slave。Master也可以部署多个。每个Broker与NameServer集群中的所有节点建立长连接,定时注册Topic信息到所有NameServer。
- Producer消息生产者,与NameServer集群中的其中一个节点(随机选择)建立长连接,定期从NameServer获取Topic路由信息,并向提供Topic 服务的Broker中的Master建立长连接,且定时向Master发送心跳。Producer完全无状态,可集群部署。
- Consumer消息消费者,与NameServer集群中的其中一个节点(随机选择)建立长连接,定期从NameServer获取Topic路由信息,并向提供Topic服务的Master、Slave建立长连接,且定时向Master、Slave发送心跳。Consumer既可以从Master订阅消息,也可以从Slave订阅消息,消费者在向Master拉取消息时,Master服务器会根据拉取偏移量与最大偏移量的距离(判断是否读老消息,产生读I/O),以及从服务器是否可读等因素建议下一次是从Master还是Slave拉取。
工作流程
- 启动NameServer,NameServer起来后监听端口,等待Broker、Producer、Consumer连上来,相当于一个路由控制中心。
- Broker启动,跟所有的NameServer保持长连接,定时发送心跳包。心跳包中包含当前Broker信息(IP+端口等)以及存储所有Topic信息。注册成功后,NameServer集群中就有Topic跟Broker的映射关系。
收发消息前,先创建Topic,创建Topic时需要指定该Topic要存储在哪些Broker上,也可以在发送消息时自动创建Topic。 - Producer发送消息,启动时先跟NameServer集群中的其中一台建立长连接,并从NameServer中获取当前发送的Topic存在哪些Broker上,轮询从队列列表中选择一个队列,然后与队列所在的Broker建立长连接从而向Broker发消息。
- Consumer跟Producer类似,跟其中一台NameServer建立长连接,获取当前订阅Topic存在哪些Broker上,然后直接跟Broker建立连接通道,开始消费消息。
入门使用
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.7.0</version>
</dependency>
Producer
package com.lb.base;
import 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;
public class BaseProducer {
public static void main(String[] args) throws Exception {
//1.创建生产者
DefaultMQProducer producer = new DefaultMQProducer("my-producer-group1");
//2.生产者指定nameserver的地址
producer.setNamesrvAddr("192.168.99.100:9876");
//3.启动生产者
producer.start();
//4.创建消息
for (int i = 0; i < 10; i++) {
Message message =
new Message("Mytopic1", "TagA",
("hello rocketmq" + i).getBytes(StandardCharsets.UTF_8));
//5.发送方法
SendResult sendResult = producer.send(message);
System.out.println(sendResult);
}
//6.关闭生产者
producer.shutdown();
}
}
结果:
RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).
RocketMQLog:WARN Please initialize the logger system properly.
SendResult [sendStatus=SEND_OK, msgId=C0A80066158414DAD5DC885868AE0000, offsetMsgId=C0A8636400002A9F0000000000000000, messageQueue=MessageQueue [topic=Mytopic1, brokerName=broker-a, queueId=1], queueOffset=0]
SendResult [sendStatus=SEND_OK, msgId=C0A80066158414DAD5DC8858690F0001, offsetMsgId=C0A8636400002A9F00000000000000B0, messageQueue=MessageQueue [topic=Mytopic1, brokerName=broker-a, queueId=2], queueOffset=0]
SendResult [sendStatus=SEND_OK, msgId=C0A80066158414DAD5DC885869150002, offsetMsgId=C0A8636400002A9F0000000000000160, messageQueue=MessageQueue [topic=Mytopic1, brokerName=broker-a, queueId=3], queueOffset=0]
SendResult [sendStatus=SEND_OK, msgId=C0A80066158414DAD5DC885869220003, offsetMsgId=C0A8636400002A9F0000000000000210, messageQueue=MessageQueue [topic=Mytopic1, brokerName=broker-a, queueId=0], queueOffset=0]
SendResult [sendStatus=SEND_OK, msgId=C0A80066158414DAD5DC885869260004, offsetMsgId=C0A8636400002A9F00000000000002C0, messageQueue=MessageQueue [topic=Mytopic1, brokerName=broker-a, queueId=1], queueOffset=1]
SendResult [sendStatus=SEND_OK, msgId=C0A80066158414DAD5DC8858692B0005, offsetMsgId=C0A8636400002A9F0000000000000370, messageQueue=MessageQueue [topic=Mytopic1, brokerName=broker-a, queueId=2], queueOffset=1]
SendResult [sendStatus=SEND_OK, msgId=C0A80066158414DAD5DC8858692F0006, offsetMsgId=C0A8636400002A9F0000000000000420, messageQueue=MessageQueue [topic=Mytopic1, brokerName=broker-a, queueId=3], queueOffset=1]
SendResult [sendStatus=SEND_OK, msgId=C0A80066158414DAD5DC885869390007, offsetMsgId=C0A8636400002A9F00000000000004D0, messageQueue=MessageQueue [topic=Mytopic1, brokerName=broker-a, queueId=0], queueOffset=1]
SendResult [sendStatus=SEND_OK, msgId=C0A80066158414DAD5DC8858693C0008, offsetMsgId=C0A8636400002A9F0000000000000580, messageQueue=MessageQueue [topic=Mytopic1, brokerName=broker-a, queueId=1], queueOffset=2]
SendResult [sendStatus=SEND_OK, msgId=C0A80066158414DAD5DC885869410009, offsetMsgId=C0A8636400002A9F0000000000000630, messageQueue=MessageQueue [topic=Mytopic1, brokerName=broker-a, queueId=2], queueOffset=2]
Process finished with exit code 0
注意:
根据结果可以发现,一个队列默认创建四个队列用来存储消息,如果是集群状态每个broker都存在4个队列消息会分布在所有broker的所有队列上,我的rocketmq只启动了一个broker所以消息都在这个broker的4个队列里面。
当我们指明topic时,如果topic本身不存在,需要rocketmq帮我们创建主题,则需要配置文件开启
#是否允许Broker自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
Consumer
package com.lb.base;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.*;
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 Exception {
//1.创建消费者对象
DefaultMQPushConsumer consumer =
new DefaultMQPushConsumer("my-consumer-group1");
//2.指明nameserver地址
consumer.setNamesrvAddr("192.168.99.100:9876");
//3.consumer订阅主题Mytopic1下的TagA标签的消息
//参数2 subExpression代表过滤消息的表达式
consumer.subscribe("Mytopic1", "TagA");
//订阅主题Mytopic1下所有消息
// consumer.subscribe("Mytopic1", "*");
//4.创建一个监听器,当broker把消息推过来调用
consumer.registerMessageListener(new MessageListenerConcurrently(){
&#