RocketMq快速实战

一、MQ简介

MQ:MessageQueue,消息队列。是在互联网中使用非常广泛的一系列服务中间件。 这个词可以分两个部分来看,一是Message:消息。消息是在不同进程之间传递的数据。这些进程可以部署在同一台机器上,也可以分布在不同机器上。二是Queue:队列。队列原意是指一种具有FIFO(先进先出)特性的数据结构,是用来缓存数据的。对于消息中间件产品来说,能不能保证FIFO特性,尚值得考量。但是,所有消息队列都是需要具备存储消息,让消息排队的能力。

​ 广义上来说,只要能够实现消息跨进程传输以及队列数据缓存,就可以称之为消息队列。例如我们常用的QQ、微信、阿里旺旺等就都具备了这样的功能。只不过他们对接的使用对象是人,而我们这里讨论的MQ产品需要对接的使用对象是应用程序。

MQ的作用主要有以下三个方面:

  • 异步

    例子:快递员发快递,直接到客户家效率会很低。引入菜鸟驿站后,快递员只需要把快递放到菜鸟驿站,就可以继续发其他快递去了。客户再按自己的时间安排去菜鸟驿站取快递。

    作用:异步能提高系统的响应速度、吞吐量。

  • 解耦

    例子:《Thinking in JAVA》很经典,但是都是英文,我们看不懂,所以需要编辑社,将文章翻译成其他语言,这样就可以完成英语与其他语言的交流。

    作用:

    1、服务之间进行解耦,才可以减少服务之间的影响。提高系统整体的稳定性以及可扩展性。

    2、另外,解耦后可以实现数据分发。生产者发送一个消息后,可以由一个或者多个消费者进行消费,并且消费者的增加或者减少对生产者没有影响。

  • 削峰

    例子:长江每年都会涨水,但是下游出水口的速度是基本稳定的,所以会涨水。引入三峡大坝后,可以把水储存起来,下游慢慢排水。

    作用:以稳定的系统资源应对突发的流量冲击。

二、RocketMQ产品特点

1、RocketMQ介绍

​ RocketMQ是阿里巴巴开源的一个消息中间件,在阿里内部历经了双十一等很多高并发场景的考验,能够处理亿万级别的消息。2016年开源后捐赠给Apache,现在是Apache的一个顶级项目。

​ 早期阿里使用ActiveMQ,但是,当消息开始逐渐增多后,ActiveMQ的IO性能很快达到了瓶颈。于是,阿里开始关注Kafka。但是Kafka是针对日志收集场景设计的,他的高级功能并不是很贴合阿里的业务场景。尤其当他的Topic过多时,由于Partition文件也会过多,这就会加大文件索引的耗时,会严重影响IO性能。于是阿里才决定自研中间件,最早叫做MetaQ,后来改名成为RocketMQ。最早他所希望解决的最大问题就是多Topic下的IO性能压力。但是产品在阿里内部的不断改进,RocketMQ开始体现出一些不一样的优势。

2、RocketMQ特点

​ 当今互联网MQ产品众多,其中,影响力和使用范围最大的当数Apache Kafka、RabbitMQ、Apache RocketMQ以及Apache Plusar。这几大产品虽然都是典型的MQ产品,但是由于设计和实现上的一些差异,造成他们适合于不同的细分场景。

其中RocketMQ,孵化自阿里巴巴。历经阿里多年双十一的严格考验,RocketMQ可以说是从全世界最严苛的高并发场景中摸爬滚打出来的过硬产品,也是少数几个在金融场景比较适用的MQ产品。从横向对比来看,RocketMQ与Kafka和RabbitMQ相比。RocketMQ的消息吞吐量虽然和Kafka相比还是稍有差距,但是却比RabbitMQ高很多。在阿里内部,RocketMQ集群每天处理的请求数超过5万亿次,支持的核心应用超过3000个。而RocketMQ最大的优势就是他天生就为金融互联网而生。他的消息可靠性相比Kafka也有了很大的提升,而消息吞吐量相比RabbitMQ也有很大的提升。另外,RocketMQ的高级功能也越来越全面,广播消费、延迟队列、死信队列等等高级功能一应俱全,甚至某些业务功能比如事务消息,已经呈现出领先潮流的趋势。

三、RocketMQ快速实战

1、快速搭建RocketMQ服务

RocketMQ的官网地址: rocketmq.apache.org 。在下载页面可以获取RocketMQ的源码包以及运行包。下载页面地址:rocketmq.apache.org/download。

​ 当前最新的版本是5.x,这是一个着眼于云原生的新版本,给 RocketMQ 带来了非常多很亮眼的新特性。但是目前来看,企业中用得还比较少。因此,我们这里采用的还是更为稳定的4.9.5版本。

注:在2020年下半年,RocketMQ新推出了5.0的大版本,这对于RocketMQ来说,是一个里程碑式的大版本。在这个大版本中,RocketMQ对整体功能做了一次大的升级。增加了很多非常有用的新特性,也对已有功能重新做了升级。

​ 比如在具体功能方面,在4.x版本中,对于定时消息,只能设定几个固定的延迟级别,而5.0版本中,已经可以指定具体的发送时间了。在客户端语言方面,4.x版本,RocketMQ原生只支持基于Netty框架的Java客户端。而在5.0版本中,增加了对Grpc协议的支持,这基本上就解除了对客户端语言的限制。在服务端架构方面,4.x版本只支持固定角色的普通集群和可以动态切换角色的Dledger集群,而在5.0版本中,增加了Dledger Controller混合集群模式,即可以混合使用Dledger的集群机制以及 Broker 本地的文件管理机制。

​ 但是功能强大,同时也意味着问题会很多。所以目前来看,企业中直接用新版本的还比较少。小部分使用新版本的企业,也大都是使用内部的改造优化版本。

​ 运行只需要下载Binary运行版本就可以了。 当然,源码包也建议下载下来,后续会进行解读。运行包下载下来后,就可以直接解压,上传到服务器上。我们这里会上传到/app/rocketmq目录。解压后几个重要的目录如下:

接下来,RocketMQ建议的运行环境需要至少12G的内存,这是生产环境比较理想的资源配置。但是,学习阶段,如果你的服务器没有这么大的内存空间,那么就需要做一下调整。进入bin目录,对其中的runserver.sh和runbroker.sh两个脚本进行一下修改。

​ 使用vi runserver.sh指令,编辑这个脚本,找到下面的一行配置,调整Java进程的内存大小。

ini 复制代码
JAVA_OPT="${JAVA_OPT} -server -Xms512m -Xmx512m -Xmn256m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"

​ 接下来,同样调整runbroker.sh中的内存大小。

ini 复制代码
JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g"
修改为:
JAVA_OPT="${JAVA_OPT} -server -Xms1g -Xmx1g"

生产环境不建议调整。

​ 调整完成后,就可以启动RocketMQ服务了。 RocketMQ服务基于Java开发,所以需要提前安装JDK。JDK建议采用1.8版本即可。

Java环境安装略过。

​ RocketMQ的后端服务分为nameserver和broker两个服务,关于他们的作用,后面会给你分享。接下来我们先将这两个服务启动起来。

第一步:启动nameserver服务。

bash 复制代码
cd /app/rocketmq/rocketmq-all-4.9.5-bin-release
nohup bin/mqnamesrv &

​ 指令执行后,会生成一个nohup.out的日志文件。在这个日志文件里如果看到下面这一条关键日志,就表示nameserver服务启动成功了。

vbscript 复制代码
Java HotSpot(TM) 64-Bit Server VM warning: Using the DefNew young collector 
with the CMS 
collector is deprecated and will likely be removed in a future release 
Java HotSpot(TM) 64-Bit Server VM warning: UseCMSCompactAtFullCollection is 
deprecated and 
will likely be removed in a future release. 
The Name Server boot success. serializeType=JSON 

接下来,可以通过jsp指令进行验证。使用jps指令后,可以看到有一个NamesrvStartup的进程运行,也表示nameserver服务启动完成。

第二步:启动broker服务。

​ 启动broker服务之前,要做一个小小的配置。进入RocketMQ安装目录下的conf目录,修改broker.conf文件,在文件最后面加入一个配置:

ini 复制代码
autoCreateTopicEnable=true

这个选项是为了便于进行后续实验。他的作用是允许 broker 端自动创建新的 Topic。

另外,如果你的服务器配置了多张网卡,比如阿里云,腾讯云这样的云服务器,他们通常有内网网卡和外网网卡两张网卡,那么需要增加配置brokerIP1属性,指向服务器的外网IP 地址,这样才能确保从其他服务器上访问到RocketMQ 服务。

然后也可以用之前的方式启动broker服务。启动broker服务的指令是mqbroker

bash 复制代码
cd /app/rocketmq/rocketmq-all-4.9.5-bin-release
nohup bin/mqbroker &

启动完成后,同样检查nohup.out日志文件,有如下一条关键日志,就表示broker服务启动正常了。

ini 复制代码
The broker[xxxxx] boot success. serializeType=JSON 

注:1、在实际服务部署时,通常会将RocketMQ的部署地址添加到环境变量当中。例如使用vi ~/.bash_profile指令,添加以下内容。

export ROCKETMQ_HOME=/app/rocketmq/rocketmq-all-4.9.5-bin-releasePATH= <math xmlns="http://www.w3.org/1998/Math/MathML"> R O C K E T M Q H O M E / b i n : ROCKETMQ_HOME/bin: </math>ROCKETMQHOME/bin:PATHexport PATH

这样就不必每次进入RocketMQ的安装目录了。直接可以使用mqnamesrv 和mqbroker指令。

2、停止RocketMQ服务可以通过mqshutdown指令进行

mqshutdown namesrv # 关闭nameserver服务

mqshutdown broker # 关闭broker服务

​ 同样使用jps指令可以检查服务的启动状态。使用jsp指令后,可以看到一个名为BrokerStartup的进程,则表示broker服务启动完成。

2、快速实现消息收发

​ RocketMQ后端服务启动完成后,就可以启动客户端的消息生产者和消息消费者进行消息转发了。接下来,我们会先通过RocketMQ提供的命令行工具快速体验一下RocketMQ消息收发的功能。然后,再动手搭建一个Maven项目,在项目中使用RocketMQ进行消息收发。

1、命令行快速实现消息收发

第一步:需要配置一个环境变量NAMESRV_ADDR,只想我们之前启动的nameserver服务。

通过vi ~/.bash_profile添加以下配置。然后使用source ~/.bash_profile让配置生效。

ini 复制代码
export NAMESRV_ADDR='localhost:9876' 

第二步:通过指令启动RocketMQ的消息生产者发送消息。

复制代码
tools.sh org.apache.rocketmq.example.quickstart.Producer 

这个指令会默认往RocketMQ中发送1000条消息。在命令行窗口可以看到发送消息的日志:

ini 复制代码
.....
SendResult [sendStatus=SEND_OK, msgId=C0A8E88007AC3764951D891CE9A003E7, 
offsetMsgId=C0A8E88000002A9F00000000000317BF, messageQueue=MessageQueue 
[topic=TopicTest, brokerName=worker1, queueId=1], queueOffset=249] 

14:59:33.418 [NettyClientSelector_1] INFO RocketmqRemoting - closeChannel: 
close the connection to remote address[127.0.0.1:9876] result: true 

14:59:33.423 [NettyClientSelector_1] INFO RocketmqRemoting - closeChannel: 
close the connection to remote address[192.168.232.128:10911] result: true

​ 这部分日志中,并没有打印出发送了什么消息。上面SendResult开头部分是消息发送到Broker后的结果。最后两行日志表示消息生产者发完消息后,服务正常关闭了。

第三步:可以启动消息消费者接收之前发送的消息

复制代码
tools.sh org.apache.rocketmq.example.quickstart.Consumer

消费者启动完成后,可以看到消费到的消息

makefile 复制代码
...... 
ConsumeMessageThread_19 Receive New Messages: [MessageExt 
[brokerName=worker1, queueId=2, storeSize=203, queueOffset=53, sysFlag=0, 
bornTimestamp=1606460371999, bornHost=/192.168.232.128:43436, 
storeTimestamp=1606460372000, storeHost=/192.168.232.128:10911, 
msgId=C0A8E88000002A9F000000000000A7AE, commitLogOffset=42926, 
bodyCRC=1968636794, reconsumeTimes=0, preparedTransactionOffset=0, 
toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=0, 
MAX_OFFSET=250, CONSUME_START_TIME=1606460450150, 
UNIQ_KEY=C0A8E88007AC3764951D891CE41F00D4, CLUSTER=DefaultCluster, 
WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 
101, 116, 77, 81, 32, 50, 49, 50], transactionId='null'}]] 

​ 每一条这样的日志信息就表示消费者接收到了一条消息。

​ 这个Consumer消费者的指令并不会主动结束,他会继续挂起,等待消费新的消息。我们可以使用CTRL+C停止该进程。

注:在RocketMQ提供的这个简单示例中并没有打印出传递的消息内容,而是打印出了消息相关的很多重要的属性。

其中有几个比较重要的属性: brokerId,brokerName,queueId,msgId,topic,cluster。这些属性的作用会在后续一起分享,这里你不妨先找一下这些属性是什么,消费者与生产者之间有什么样的对应关系。

相关推荐
Marktowin1 小时前
Mybatis-Plus更新操作时的一个坑
java·后端
赵文宇2 小时前
CNCF Dragonfly 毕业啦!基于P2P的镜像和文件分发系统快速入门,在线体验
后端
程序员爱钓鱼2 小时前
Node.js 编程实战:即时聊天应用 —— WebSocket 实现实时通信
前端·后端·node.js
Libby博仙3 小时前
Spring Boot 条件化注解深度解析
java·spring boot·后端
源代码•宸3 小时前
Golang原理剖析(Map 源码梳理)
经验分享·后端·算法·leetcode·golang·map
小周在成长3 小时前
动态SQL与MyBatis动态SQL最佳实践
后端
瓦尔登湖懒羊羊3 小时前
TCP的自我介绍
后端
小周在成长3 小时前
MyBatis 动态SQL学习
后端
子非鱼9213 小时前
SpringBoot快速上手
java·spring boot·后端
我爱娃哈哈4 小时前
SpringBoot + XXL-JOB + Quartz:任务调度双引擎选型与高可用调度平台搭建
java·spring boot·后端