前言
RocketMQ是阿里巴巴团队研发的高性能、分布式消息中间件,已捐赠给Apache基金会,面向所有开发人员开源免费使用,本文主要参考其官方快速文档(http://jm.taobao.org/2017/01/12/rocketmq-quick-start-in-10-minutes/)和自己亲自动手实践,我们从了解RocketMQ开始,循序渐进,一步一步亲自实现中间件部署,测试消息收发,从理论和实践两方面学会使用RocketMQ。
1.RocketMQ 是什么?
上图是一个典型的消息中间件收发消息的模型,RocketMQ也是这样的设计,简单说来,RocketMQ具有以下特点:
o 是一个队列模型的消息中间件,具有高性能、高可靠、高实时、分布式特点。
o Producer、Consumer、队列都可以分布式。
o Producer向一些队列轮流发送消息,队列集合称为Topic,Consumer如果做广播消费,则一个consumer实例消费这个Topic对应的所有队列,如果做集群消费,则多个Consumer实例平均消费这个topic对应的队列集合。
o 能够保证严格的消息顺序
o 提供丰富的消息拉取模式
o 高效的订阅者水平扩展能力
o 实时的消息订阅机制
o 亿级消息堆积能力
o 较少的依赖
2.RocketMQ 物理部署结构
如上图所示, RocketMQ的部署结构有以下特点:
o Name Server是一个几乎无状态节点,可集群部署,节点之间无任何信息同步。
o Broker部署相对复杂,Broker分为Master与Slave,一个Master可以对应多个Slave,但是一个Slave只能对应一个Master,Master与Slave的对应关系通过指定相同的BrokerName,不同的BrokerId来定义,BrokerId为0表示Master,非0表示Slave。Master也可以部署多个。每个Broker与Name Server集群中的所有节点建立长连接,定时注册Topic信息到所有Name Server。
o Producer与Name Server集群中的其中一个节点(随机选择)建立长连接,定期从Name Server取Topic路由信息,并向提供Topic服务的Master建立长连接,且定时向Master发送心跳。Producer完全无状态,可集群部署。
o Consumer与Name Server集群中的其中一个节点(随机选择)建立长连接,定期从Name Server取Topic路由信息,并向提供Topic服务的Master、Slave建立长连接,且定时向Master、Slave发送心跳。Consumer既可以从Master订阅消息,也可以从Slave订阅消息,订阅规则由Broker配置决定。
3.RocketMQ 逻辑部署结构
如上图所示,RocketMQ的逻辑部署结构有Producer和Consumer两个特点。
Producer Group
用来表示一个发送消息应用,一个Producer Group下包含多个Producer实例,可以是多台机器,也可以是一台机器的多个进程,或者一个进程的多个Producer对象。一个Producer Group可以发送多个Topic消息,Producer Group作用如下:
1. 标识一类Producer
2. 可以通过运维工具查询这个发送消息应用下有多个Producer实例
3. 发送分布式事务消息时,如果Producer中途意外宕机,Broker会主动回调Producer Group内的任意一台机器来确认事务状态。
Consumer Group
用来表示一个消费消息应用,一个Consumer Group下包含多个Consumer实例,可以是多台机器,也可以是多个进程,或者是一个进程的多个Consumer对象。一个Consumer Group下的多个Consumer以均摊方式消费消息,如果设置为广播方式,那么这个Consumer Group下的每个实例都消费全量数据。
4.RocketMQ 数据存储结构
如上图所示,RocketMQ采取了一种数据与索引分离的存储方法。有效降低文件资源、IO资源,内存资源的损耗。即便是阿里这种海量数据,高并发场景也能够有效降低端到端延迟,并具备较强的横向扩展能力。
5.RocketMQ安装前准备
安装环境
² 64位操作系统,最好有Linux / Unix / Mac;
² 64bit JDK 1.8+;
² Maven 3.x
² Git
注:官方文档上是从GitHub上跟新代码到本地编译的方式安装的,如果是直接下载安装包的方式安装,则不需要Maven和Git,本次安装采用下载安装包的方式安装,操作系统是CentOS7,JDK8,另外在JDK9上RocketMQ会出现启动nameserver异常,日志如下,vm创建失败,网上还没找到解决办法,等后续版本加强对JDK9的支持再用会比较好。
6.RocketMQ安装步骤
①JDK的安装与配置
从Oracle官网上下载最新的jdk-9.0.1,下载地址如下:
http://www.oracle.com/technetwork/java/javase/downloads/index.html
解压到指定目录:
tar -zxvf jdk-9.0.1_linux-x64_bin.tar.gz -C /usr/local/java
配置环境变量需要在/etc/profile文件最下方添加以下内容即可:
保存退出后,在命令行输入Java -version查看版本号,能查到说明JDK安装配置成功。
②RocketMQ安装配置
从Apache官网上下载RocketMQ的安装包,下载地址如下:
http://rocketmq.apache.org/dowloading/releases/
我们下载二进制编译包即可:
将其上传至服务器,解压到制定目录:
unzip rocketmq-all-4.1.0-incubating-bin-release.zip
cp -r rocketmq-all-4.1.0-incubating /usr/local/rocketmq
rm -rf rocketmq-all-4.1.0-incubating
RocketMQ的文件结构如下:
配置RocketMQ的环境变量,vi /etc/profile,在文件底部添加以下内容:
NAMESRV_ADDR可以不在此绑定,但必须在启动broker时加上“-n 服务器IP:端口”以绑定nameserver,本次实验就直接绑定以简化操作,9876是nameserver的默认端口。
最后输入以下命令source /etc/profile,使配置生效,RocketMQ的安装及环境变量配置就完成了。
7.RocketMQ的部署
①Broker节点属性配置
Broker节点的配置文件在/rocketmq/conf下面,有三种配置方式:
2m-noslave: 多Master模式
2m-2s-sync: 多Master多Slave模式,同步双写
2m-2s-async:多Master多Slave模式,异步复制
不同的模式有相对应的配置方法,部署多少集群,就要相应创建多少个配置文件,我们拿多Master模式举例,进去会发现里面有两个文件:
代表两个Master,查看原始文件的内容:
里面有若干参数配置,其余均为默认配置,如果需要集群配置,需根据实际情况设置相应参数,官网给出了Broker配置的参数列表:
文档地址是http://rocketmq.apache.org/docs/rmq-deployment/
特别强调的是:如果nameserver要集群的话,要在namesrvAddr上列出所有nameserver节点的IP和端口;brokerRole要填写当前节点的角色有ASYNC_MASTER、SYNC_MASTER、SLAVE三种。
配置实例请参考以下博客:
http://blog.csdn.net/xiaojie19871116/article/details/46982907
②启动nameserver
在ROCKET_HOME路径下执行命令nohup sh mqnamesrv &
在启动状态执行查询命令tail -f ~/logs/rocketmqlogs/namesrv.log
从中可以看出nameserver启动成功。
③启动broker
在ROCKET_HOME路径下执行命令nohup sh mqbroker &
如果没有注册NAMESRV_ADDR执行nohup sh mqbroker -n服务器IP:9876 &
如有多个broker的配置文件,则还要加上启动哪个broker的配置文件,如:
nohup sh mqbroker -n 服务器IP:9876 -c $ROCKETMQ_HOME/conf/2m-noslave/broker-a.properties &
需要注意的是broker启动需要的内存较大,我设置虚拟机的时候只分配了2G内存,启动时报内存不足异常,通过cat nohup.out命令查得以下日志信息:
我们需要修改内存信息,执行查看命令cat runbroker.sh,找到# JVM Configuration处查看JAVA_OPT设置,如下图:
-Xms的值已经远大于内存和交换区的大小,我们用命令cat runserver.sh查看一下nameserver的内存配置,nameserver正常启动几乎把内存占满,
所以我们应把nameserver和broker的内存都改小,当然在实际开发环境部署时也可以根据实际需求将其改大。
Nameserver的配置如下:
Broker的配置如下:
分别启动nameserver和broker,
执行命令tail -f ~/logs/rocketmqlogs/broker.log查看broker的启动状态:
说明我们启动broker成功,broker在nameserver上也注册成功。
④关闭nameserver和broker
关闭nameserver在ROCKETMQ_HOME路径下执行以下命令:
sh mqshutdown namesrv
关闭broker在ROCKETMQ_HOME路径下执行以下命令:
sh mqshutdown broker
一般先关闭所有的broker后,再关闭nameserver。
⑤测试
RocketMQ有自带的调试工具模拟Producer和Consumer
在ROCKETMQ_HOME路径下执行以下命令模拟Producer发消息:
sh tools.sh org.apache.rocketmq.example.quickstart.Producer
会发出很多条下面的命令,说明发送成功:
在ROCKETMQ_HOME路径下执行以下命令模拟Consumer发消息:
sh tools.sh org.apache.rocketmq.example.quickstart.Consumer
会收到和上面一样多的命令,说明接收成功,可证明RocketMQ部署成功:
8.创建Producer和Consumer
RocketMQ可支持多种消息,如一般消息、定时消息、广播消息、顺序消息等,详细参见官方文档,有代码实例,本次只列出一种消息的实例。
①添加依赖
以下依赖是必须的:
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>rocketmq-common</artifactId>
<exclusions>
<exclusion>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<scope>test</scope>
</dependency>
</dependencies
②创建Producer
注:producer在使用之前需先设置nameserver的地址才能和RocketMQ通信,即:producer.setNamesrvAddr("服务器IP:9876");
③创建Consumer
注:consumer在使用之前需先设置nameserver的地址才能和RocketMQ通信,即:consumer.setNamesrvAddr("服务器IP:9876");
还有更高级的推拉消息的用法,可以从GitHub上得到源码,查看rocketmq-master\client中的Producer和Consumer的代码。