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。这些属性的作用会在后续一起分享,这里你不妨先找一下这些属性是什么,消费者与生产者之间有什么样的对应关系。

相关推荐
潘多编程1 小时前
Spring Boot微服务架构设计与实战
spring boot·后端·微服务
2402_857589362 小时前
新闻推荐系统:Spring Boot框架详解
java·spring boot·后端
2401_857622662 小时前
新闻推荐系统:Spring Boot的可扩展性
java·spring boot·后端
江湖十年3 小时前
在 Go 中如何优雅的处理错误
后端·go
Amagi.3 小时前
Spring中Bean的作用域
java·后端·spring
侠客行03173 小时前
xxl-job调度平台之任务触发
java·后端·源码
2402_857589363 小时前
Spring Boot新闻推荐系统设计与实现
java·spring boot·后端
J老熊4 小时前
Spring Cloud Netflix Eureka 注册中心讲解和案例示范
java·后端·spring·spring cloud·面试·eureka·系统架构
Benaso4 小时前
Rust 快速入门(一)
开发语言·后端·rust
sco52824 小时前
SpringBoot 集成 Ehcache 实现本地缓存
java·spring boot·后端