这是本人学习的总结,主要学习资料如下
- 马士兵教育
- rocketMq官方文档
目录
1、架构
主要有四个角色,NameServer
,Broker Cluster
,Consumer
和Producer
。
Consumer
和Producer
很容易理解,就是消费者和生产者。
NameServer
是提供注册的服务,其他的节点想要加入到一个MQ的架构中都需要在NameServer
中注册,同时也需要通过NameServer
获取服务。
Broker Cluster
则是提供消息的传输和存储。
2、基本概念
- 主题(Topic):表示一类消息,通常是业务上的某一类操作。开发时可以自定义主题的名字,最好足够贴切,比如物流消息,订单消息,能直接了当地知道消息的大概内容。
producer
和consumer
发送和消费信息时必须指明从哪个topic
中生产消费信息。 - 标签(Tag):用来更细地去划分消息的种类。比如消息的主题是手机,那对应的
tag
可能有苹果手机,谷歌手机等。
同时producer
发送消息是向一个topic
发送消息,consumer
也是从一个topic
接受消息。在rocketMQ中,tag其实是方便开发者的。因为topic
的修改需要admin权限,代码中只能用存在的topic
生产消费信息。但是tag则是可以在生产消费消息时在代码中随意指定。 - 分组(Group):一个
producer
或者一个consumer
就是一个服务节点。可能业务量过大,一个节点处理不过来,那就可以增加节点处理相同的业务,那这些处理相同业务的节点就可以分为一个group
。而一个消息可能会被多个业务组处理,比如一个订单消息会被物流,短信,数据分析等业务组处理。这些业务组就是多个group
。 - 消息队列(Message Queue):通常处理消息比发送消息要复杂,所以一个
producer
往往对应多个consumer
。为了提高并发率,消息到了topic
会被分发到多个message queue
中。同一组的每个消费者有自己的一个MQ
,他们消费消息时就可以并发进行。 - 偏移量(Offset):消息队列中有很多偏移量的概念,都是用来表示数据的多少。比如
consumerOffset
用来表示已经消费的消息个数,
3、安装和启动
3.1、命令行启动
从官网下载最新版本的Binary Package
即可,目前是5.1.0
。
根据官网手册操作即可https://rocketmq.apache.org/docs/quickStart/01quickstart/。
我自己文件放到/Library/rocketmq-all-5.1.0-bin-release
下。现在就算是安装好了,随时可以进入目录用命令行启动项目。
架构中说过RocketMQ
有四个部分分别是broker
用来保存和持久化信息,server
用来注册节点,还有就是producer
和consumer
。
下面会分别启动这四个应用。
3.1.1、启动Server
在进入编译好项目的/bin
目录下,可以用下面指令启动项目和查看日志
nohup sh mqnamesrv &
tail -f ~/logs/rocketmqlogs/namesrv.log
server
的默认端口号是9876
显示下面的内容表示启动成功
MacBook-Pro:bin user$ tail -f ~/logs/rocketmqlogs/namesrv.log
2023-03-16 21:04:56 INFO main - The Name Server boot success. serializeType=JSON
2023-03-16 21:04:56 INFO NettyClientScan_thread_1 - createChannel: begin to connect remote host[192.168.2.3:9876] asynchronously
2023-03-16 21:04:56 INFO NettyClientWorkerThread_1 - NETTY CLIENT PIPELINE: CONNECT UNKNOWN => 192.168.2.3:9876
2023-03-16 21:04:56 INFO NettyClientScan_thread_1 - createChannel: connect remote host[192.168.2.3:9876] success, AbstractBootstrap$PendingRegistrationPromise@25cfa9a3(success)
2023-03-16 21:04:56 INFO NettyServerCodecThread_1 - NETTY SERVER PIPELINE: channelRegistered 192.168.2.3:50806
2023-03-16 21:04:56 INFO NettyServerCodecThread_1 - NETTY SERVER PIPELINE: channelActive, the channel[192.168.2.3:50806]
3.1.2、启动Broker
之后到bin
目录启动文件,返回值是进程号PID
nohup sh bin/mqbroker -n localhost:9876 --enable-proxy &
[1] 59852
发现日志开始打印很多东西,往下滑,会看到当前broker
成功注册的消息,那broker
就启动成功。
2023-03-16 22:16:08 INFO main - brokerConfigPath=
2023-03-16 22:16:08 INFO main - rocketmqHome=/Library/rocketmq-all-5.1.0-bin-release
2023-03-16 22:16:08 INFO main - namesrvAddr=localhost:9876
2023-03-16 22:16:08 INFO main - listenPort=6888
2023-03-16 22:16:08 INFO main - brokerIP1=192.168.2.3
2023-03-16 22:16:08 INFO main - brokerIP2=192.168.2.3
2023-03-16 22:16:08 INFO main - brokerPermission=6
2023-03-16 22:16:08 INFO main - defaultTopicQueueNums=8
2023-03-16 22:16:08 INFO main - autoCreateTopicEnable=true
2023-03-16 22:16:08 INFO main - clusterTopicEnable=true
# 省略中间内容
2023-03-16 22:16:13 INFO brokerOutApi_thread_1 - Registering current broker to name server completed. TargetHost=localhost:9876
另外查看进程号也能验证broker
启动成功,看第一行的信息
$ ps -ef | grep 59852
501 59852 24009 0 10:16下午 ttys001 0:00.01 sh bin/mqbroker -n localhost:9876 --enable-proxy
501 59856 59852 0 10:16下午 ttys001 0:00.01 sh /Library/rocketmq-all-5.1.0-bin-release/bin/runserver.sh -Drmq.logback.configurationFile=/Library/rocketmq-all-5.1.0-bin-release/conf/rmq.proxy.logback.xml org.apache.rocketmq.proxy.ProxyStartup -n localhost:9876 -pm local
501 62270 24009 0 10:22下午 ttys001 0:00.00 grep 59852
3.1.2.1、修改初始内存
因为broker
默认会占用8g内存,某些情况下会因为内存不足而启动失败,如果需要修改内存大小需要到/bin/runbroker.sh
修改指令。
vim /bin/runbroker.sh
在99
行的位置,
JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g"
本地启用我就设成512M
JAVA_OPT="${JAVA_OPT} -server -Xms512m -Xmx512m"
3.1.3、总结
启动服务
# 启动namesrv服务
nohup sh bin/mqnamesrv &
# 查看日志
tail -f ~/logs/rocketmqlogs/namesrv.log
# 启动broker服务
nohup sh bin/mqbroker -n localhost:9876 --enable-proxy &
# 查看日志
tail -f ~/logs/rocketmqlogs/broker.log
关闭服务
# 关闭namesrv服务
sh bin/mqshutdown namesrv
# 关闭broker服务
sh bin/mqshutdown broker
3.2、启动管理系统
管理页面让我们更直观方便地管理观察MQ。
到https://github.com/apache/rocketmq-dashboard下载项目。
这是一个Maven
管理的java
项目,我们先修改配置,指定server
地址,因为这里是本地启动的server
所以就是本地地址。
配置文件是/src/main/resources/application.yml
,修改里面的配置项,指定为本地地址
rocketmq:
config:
namesrvAddr: localhost:9876
之后进入项目根目录打包
cd /Users/user/Downloads/rocketmq-dashboard-master
mvn package
启动打包好的jar
文件
java -jar rocketmq-dashboard-1.0.1-SNAPSHOT.jar
打开网页localhost:8080
。为了以后方便,我就把jar
文件放到rocketmq-all-5.1.0-bin-release
下面,启动server和broker时不用切换目录。
4、发送和接收消息样例
在上面的基础上,启动server
和broker
以后,可以开始发送和接收消息
4.1、依赖
依赖都是选择写文章时的最新版本
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.8.0</version>
</dependency>
4.2、创建topic
要注意创建修改topic
是admin
的权限,所以producer
和consumer
端不提供API修改创建topic
现在有两个方法创建topic
,一个是通过/bin/mqadmin.sh
,另一个是通过管理系统。
先说说管理系统。就在topic
页,ADD/UPDATE
,填写topicName
后提交即可。
下面是通过命令行创建topic
$ sh bin/mqadmin updateTopic -b 192.168.2.3:10911 -t topic1
create topic to 192.168.2.3:10911 success.
TopicConfig [topicName=topic1, readQueueNums=8, writeQueueNums=8, perm=RW-, topicFilterType=SINGLE_TAG, topicSysFlag=0, order=false, attributes={}]
-b 192.168.2.3:10911
是broker
的端口号,topic
必须隶属于一个cluster
或者broker
,这里只是简单的单机节点所以就指定broker
。
-t topic1
则是topicName
。
4.3、发送信息
使用下面代码发送信息。
需要先有一个producer
对象,然后producer
需要注册到server
中,设置server
地址。
然后发信息要选择topic
和tag
,最后设置message
即可发送。
public class ProducerExample {
public static void main(String[] args) throws Exception{
DefaultMQProducer producer = getProducer();
Message msg = getMessage();
SendResult sendResult = producer.send(msg);
System.out.printf("%s%n", sendResult);
producer.shutdown();
}
private static DefaultMQProducer getProducer() throws MQClientException {
DefaultMQProducer producer = new DefaultMQProducer("group1");
producer.setNamesrvAddr("localhost:9876");
producer.start();
return producer;
}
private static Message getMessage() {
Message msg = new Message();
msg.setTopic("topic1");
msg.setTags("tag1");
msg.setBody("body1".getBytes());
return msg;
}
}
输出的日志是
SendResult [sendStatus=SEND_OK, msgId=7F0000012B1818B4AAC26706B2E20000, offsetMsgId=C0A8020300002A9F000000000003ADD1, messageQueue=MessageQueue [topic=topic1, brokerName=broker-a, queueId=2], queueOffset=0]
这里我是第二次运行的截图,所以queueId=2
4.4、接受信息
这里需要有一个consumer
,consumer
也需要登记到server
,填写server
地址。
之后订阅一个topic
中的tag
(也可以不指定tag
,用*
表示),等待接受消息即可。
public class ConsumerExample {
public static void main(String[] args) throws Exception{
DefaultMQPushConsumer consumer = getConsumer();
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list
, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
boolean isSuccess = true;
try{
for(MessageExt msg: list) {
String topic = msg.getTopic();
String msgBody = new String(msg.getBody(), "utf-8");
String tag = msg.getTags();
System.out.println("from topic: " +topic + ",tag: " + tag + " receive message: " + msgBody);
}
} catch (Exception e) {
e.printStackTrace();
isSuccess = false;
}
return isSuccess? ConsumeConcurrentlyStatus.CONSUME_SUCCESS: ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
});
consumer.start();
// 不听循环,让conusmer一直监听
while(true){
}
// consumer.shutdown();
}
private static DefaultMQPushConsumer getConsumer() throws MQClientException {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer_group1");
consumer.setNamesrvAddr("localhost:9876");
// 不指定tag
consumer.subscribe("topic1", "*");
consumer.setMessageModel(MessageModel.CLUSTERING);
return consumer;
}
}
开启生产者后,发送消息就可以接收到了。