ocketMQ在阿里内部叫做Metaq(最早名为Metamorphosis,中文意思变形记,是作家卡夫卡的中篇小说代表作,可见是为了致敬Kafka)。
RocketMQ是Metaq3.0之后的开源版本。
Metaq在阿里巴巴集团内部、蚂蚁金服、菜鸟等各业务中被广泛使用,接入了上万个应用系统中。并平稳支撑了历年双十一大促(万亿级的消息),在性能、稳定性、可靠性等方面表现出色,在整个阿里技术体系和大中台战略中发挥着举足轻重的作用。
Metaq最终源于Kafka,早起借鉴了Kafka很多优秀的设计。但是由于Kafka是Scale语言编写而阿里系主要使用Java,且无法满足阿里的电商、金融业务场景,所以誓嘉(花名)团队用Java重新造轮子,并做了大量的改造和优化。
在此之前,淘宝有一款消息中间件名为Notify,目前已经逐步被Metaq所取代。
第一代的Notify主要使用了推模型,解决了事务消息;第二代的MetaQ主要使用了拉模型,解决了顺序消息和海量堆积的问题。相比起Kafka使用的Scale语言编写,RabbitMQ 使用Erlang语言编写,基于Java的RocketMQ开源后更容易被广泛的研究,以及其他大厂定制开发。
作者:左师兄zuosx
链接:https://www.jianshu.com/p/db11a702d49f
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
如图所示主题是属于最顶层的存储,所有的消息资源的定义都是在主题内,一个主题内部可以有多个队列。但主题是一个逻辑概念,并不是实际的消息容器。
主题的内部属性如下
1、主题名称:每个主题都用于自己的名称
2、队列列表:一个主题内部有多个队列,这些队列构成一个列表,
3、消息类型:主题内可以有不同的消息类型(但是一个主题能只能有一个消息类型!!)
Normal | 普通消息,消息本身无特殊语义,消息之间也没有任何关联。 |
---|---|
FIFO | 顺序消息,Apache RocketMQ 通过消息分组MessageGroup标记一组特定消息的先后顺序,可以保证消息的投递顺序严格按照消息发送时的顺序。 |
Delay | 延时消息,通过指定延时时间控制消息生产后不要立即投递,而是在延时间隔后才对消费者可见。 |
Transaction | 事务消息,Apache RocketMQ 支持分布式事务消息,支持应用数据库更新和消息调用的事务一致性保障。 |
队列是 Apache RocketMQ 中消息存储和传输的实际容器,也是 Apache RocketMQ 消息的最小存储单元。 Apache RocketMQ 的所有主题都是由多个队列组成,以此实现队列数量的水平拆分和队列内部的流式存储。
队列的主要作用如下:
队列的内部属性如下:
读写权限:
6 | 读写状态,当前队列允许读取消息和写入消息。 |
---|---|
4 | 只读状态,当前队列只允许读取消息,不允许写入消息。 |
2 | 只写状态,当前队列只允许写入消息,不允许读取消息。 |
0 | 不可读写状态,当前队列不允许读取消息和写入消息。 |
消息是数据的基本载体,是RocketMQ中的最小数据传输单元,生产者将业务数据的负载和拓展属性包装成消息发送到 Apache RocketMQ 服务端,服务端按照相关语义将消息投递到消费端进行消费。在RocketMQ中消息具有以下两个特征:
顾名思义生产者是消息的生产方,消息由生产者生产然后投递到消息队列中,再由消费者消费。在RocketMQ中生产者和主题是多对多的关系,即一个生产者可以对应多个Topic而一个Topic也可以对应多个生产者。
不难理解消费者组就是由若干个消费者组合而成的一个群组,这些消费者的消费行为一致(换句话说执行的是相同的业务逻辑)和消费者不同,消费者分组并不是运行实体,而是一个逻辑资源。在 Apache RocketMQ 中,通过消费者分组内初始化多个消费者实现消费性能的水平扩展以及高可用容灾。
在消费者分组中,统一定义以下消费行为,同一分组下的多个消费者将按照分组内统一的消费行为和负载均衡策略消费消息。
消费者是 Apache RocketMQ 中用来接收并处理消息的运行实体。 消费者通常被集成在业务系统中,从 Apache RocketMQ 服务端获取消息,并将消息转化成业务可理解的信息,供业务逻辑处理。
订阅关系是 Apache RocketMQ 系统中消费者获取消息、处理消息的规则和状态配置。
订阅关系由消费者分组动态注册到服务端系统,并在后续的消息传输中按照订阅关系定义的过滤规则进行消息匹配和消费进度维护。
1、下载源码
地址:https://www.apache.org/dyn/closer.cgi?path=rocketmq/5.0.0/rocketmq-all-5.0.0-source-release.zip
(可以使用wget、或者直接下载到本地上传到服务器)
2、解压
unzip rocketmq-all-5.0.0-source-release.zip
3、进入解压后的目录,编译构建Maven
cd rocketmq-all-5.0.0-source-release/
mvn -Prelease-all -DskipTests clean install -U (该过程需要一定时间)
cd distribution/target/rocketmq-5.0.0/rocketmq-5.0.0
(当然也可以直接使用编译完成的,这样就可以省去mvn的过程)
4、启动NameServer
(为了方便这里把名称改成 rocketmq-5.0.0,并且进入bin目录)
启动NameServer: nohup sh mqnamesrv &
查看是否启动成功:tail -f ~/logs/rocketmqlogs/namesrv.log
5、启动Broker+Proxy (注意:此时我们在bin目录下)
nohup sh mqbroker -n localhost:9876 --enable-proxy &
查看是否启动成功
tail -f ~/logs/rocketmqlogs/broker_default.log
至此,一个单节点副本的 RocketMQ 集群已经部署起来了
1、创建一个测试Topic
(注意路径!)
sh mqadmin updatetopic -n localhost:9876 -t TestTopic
查看是否创建成功
命令:sh mqadmin topicList -n localhost:9876
2、添加Maven依赖
<dependency>
<groupId>org.apache.rocketmqgroupId>
<artifactId>rocketmq-client-javaartifactId>
<version>5.0.0version>
dependency>
3、生产者代码
package com.cmxy.learnrocket;
import org.apache.rocketmq.client.apis.ClientConfiguration;
import org.apache.rocketmq.client.apis.ClientConfigurationBuilder;
import org.apache.rocketmq.client.apis.ClientException;
import org.apache.rocketmq.client.apis.ClientServiceProvider;
import org.apache.rocketmq.client.apis.message.Message;
import org.apache.rocketmq.client.apis.producer.Producer;
import org.apache.rocketmq.client.apis.producer.SendReceipt;
/**
* 生产者
*/
public class ProducerExample {
public static void main(String[] args) throws ClientException {
//接入点地址,需要设置成Proxy的地址和端口列表,一般是xxx:8081;xxx:8081。
String endpoint = "192.168.111.140:8081";
//消息发送的目标Topic名称,需要提前创建。
String topic = "TopicTest";
ClientServiceProvider provider = ClientServiceProvider.loadService();
ClientConfigurationBuilder builder = ClientConfiguration.newBuilder().setEndpoints(endpoint);
ClientConfiguration configuration = builder.build();
//初始化Producer时需要设置通信配置以及预绑定的Topic。
Producer producer = provider.newProducerBuilder()
.setTopics(topic)
.setClientConfiguration(configuration)
.build();
//普通消息发送。
Message message = provider.newMessageBuilder()
.setTopic(topic)
//设置消息索引键,可根据关键字精确查找某条消息。
.setKeys("messageKey")
//设置消息Tag,用于消费端根据指定Tag过滤消息。
.setTag("messageTag")
//消息体。
.setBody("messageBody".getBytes())
.build();
try {
//发送消息,需要关注发送结果,并捕获失败等异常。
SendReceipt sendReceipt = producer.send(message);
System.out.println(sendReceipt.getMessageId());
} catch (ClientException e) {
e.printStackTrace();
}
}
}
package com.cmxy.learnrocket;
import org.apache.rocketmq.client.apis.*;
import org.apache.rocketmq.client.apis.consumer.ConsumeResult;
import org.apache.rocketmq.client.apis.consumer.FilterExpression;
import org.apache.rocketmq.client.apis.consumer.FilterExpressionType;
import org.apache.rocketmq.client.apis.consumer.PushConsumer;
import java.io.IOException;
import java.util.Collections;
import org.apache.rocketmq.shaded.com.google.protobuf.InvalidProtocolBufferException;
import org.apache.rocketmq.shaded.org.slf4j.Logger;
import org.apache.rocketmq.shaded.org.slf4j.LoggerFactory;
import java.util.Collections;
/**
* 消费者
*/
public class PushConsumerExample {
private static final Logger LOGGER = LoggerFactory.getLogger(PushConsumerExample.class);
private PushConsumerExample() {
}
public static void main(String[] args) throws ClientException, InterruptedException {
final ClientServiceProvider provider = ClientServiceProvider.loadService();
//接入点地址,需要设置成Proxy的地址和端口列表,一般是xxx:8081;xxx:8081。
String endpoints = "192.168.111.140:8081";
ClientConfiguration clientConfiguration = ClientConfiguration.newBuilder()
.setEndpoints(endpoints)
.build();
//订阅消息的过滤规则,表示订阅所有Tag的消息。
String tag = "*";
FilterExpression filterExpression = new FilterExpression(tag, FilterExpressionType.TAG);
//为消费者指定所属的消费者分组,Group需要提前创建。
String consumerGroup = "TestGroup";
//指定需要订阅哪个目标Topic,Topic需要提前创建。
String topic = "TopicTest";
//初始化PushConsumer,需要绑定消费者分组ConsumerGroup、通信参数以及订阅关系。
PushConsumer pushConsumer = provider.newPushConsumerBuilder()
.setClientConfiguration(clientConfiguration)
//设置消费者分组。
.setConsumerGroup(consumerGroup)
//设置预绑定的订阅关系。
.setSubscriptionExpressions(Collections.singletonMap(topic, filterExpression))
//设置消费监听器。
.setMessageListener(messageView -> {
//处理消息并返回消费结果。
System.out.println("Consume message!!"+messageView.getBody().toString());
return ConsumeResult.SUCCESS;
}).build();
Thread.sleep(Long.MAX_VALUE);
//如果不需要再使用PushConsumer,可关闭该进程。
//pushConsumer.close();
}
}
本文简单介绍了RocketMQ,以及编写了Java客户端的简答事例,接下里会整合到其他框架,并进行进一步的学习,希望对你有所帮助。