RocketMQ集群部署笔记

RocketMQ集群(2m-2s-async)部署笔记

背景介绍

随着时间推移和数据的累积,老项目中的ActiveMQ的缺点越来越明显了。主要表现在:队列增多、消息堆积、吞吐量下降甚至出现了消息丢失等一系列问题;结合这几天对消息中间件的调研最终决定使用RocketMQ(集群部署)替代ActiveMQ(迁移工作笔记后续补充)。

使用RocketMQ的原因

  • 灵活的分布式横向扩展部署架构,低延迟、高可靠

  • 海量消息堆积能力

  • 提供丰富的消息拉取模式,支持严格顺序消息、事务消息、定时消息等,提供各种消息过滤器机制,例如Tag和SQL

  • 功能丰富的Dashboard,用于配置、指标监控

  • 开源社区活跃,成熟(经过双十一考验)

  • 等等….

官网介绍:https://rocketmq.apache.org/docs/motivation

RocketMQ的几种角色

Q8jLC9.png

  • Producer:消息发布的角色,支持分布式集群方式部署。Producer通过MQ的负载均衡模块选择相应的Broker集群队列进行消息投递,投递的过程支持快速失败并且低延迟。
  • Consumer:消息消费的角色,支持分布式集群方式部署。支持以push推,pull拉两种模式对消息进行消费。同时也支持集群方式和广播方式的消费,它提供实时消息订阅机制,可以满足大多数用户的需求。
  • NameServer:NameServer 是一个非常简单的Topic路由注册中心,其角色类似Dubbo中的zookeeper,支持Broker的动态注册与发现。主要包括两个功能:Broker管理,NameServer接受Broker集群的注册信息并且保存下来作为路由信息的基本数据。然后提供心跳检测机制,检查Broker是否还存活;路由信息管理,每个NameServer将保存关于 Broker集群的整个路由信息和用于客户端查询的队列信息。然后Producer和Conumser通过NameServer就可以知道整个Broker集群的路由信息,从而进行消息的投递和消费。NameServer通常也是集群的方式部署,各实例间相互不进行信息通讯。Broker是向每一台NameServer注册自己的路由信息,所以每一个NameServer实例上面都保存一份完整的路由信息。当某个NameServer因某种原因下线了,Broker仍然可以向其它NameServer同步其路由信息,Producer,Consumer仍然可以动态感知Broker的路由的信息。
  • BrokerServer:Broker主要负责消息的存储、投递和查询以及服务高可用保证。

几种集群搭建模式

1.单Master模式

这种方式风险较大,一旦Broker重启或者宕机时,会导致整个服务不可用。不建议线上环境使用,可以用于本地测试。

2.多Master模式

一个集群无Slave,全是Master,例如2个Master或者3个Master,这种模式的优缺点如下:

  • 优点:配置简单,单个Master宕机或重启维护对应用无影响,在磁盘配置为RAID10时,即使机器宕机不可恢复情况下,由于RAID10磁盘非常可靠,消息也不会丢(异步刷盘丢失少量消息,同步刷盘一条不丢),性能最高;
  • 缺点:单台机器宕机期间,这台机器上未被消费的消息在机器恢复之前不可订阅,消息实时性会受到影响。

3.多Master多Slave模式-异步复制

每个Master配置一个Slave,有多对Master-Slave,HA采用异步复制方式,主备有短暂消息延迟(毫秒级),这种模式的优缺点如下:

  • 优点:即使磁盘损坏,消息丢失的非常少,且消息实时性不会受影响,同时Master宕机后,消费者仍然可以从Slave消费,而且此过程对应用透明,不需要人工干预,性能同多Master模式几乎一样;
  • 缺点:Master宕机,磁盘损坏情况下会丢失少量消息。

4.多Master多Slave模式-同步双写

每个Master配置一个Slave,有多对Master-Slave,HA采用同步双写方式,即只有主备都写成功,才向应用返回成功,这种模式的优缺点如下:

  • 优点:数据与服务都无单点故障,Master宕机情况下,消息无延迟,服务可用性与数据可用性都非常高;
  • 缺点:性能比异步复制模式略低(大约低10%左右),发送单个消息的RT会略高,且目前版本在主节点宕机后,备机不能自动切换为主机。

2m-2s-sync模式搭建记录

我们采用的是2m-2s-async()模式进行集群(也就是2个Master和2个Slave-异步复制的模式)。双主双从一般有两种模式:异步复制和同步双写。同步双写就是,当生产端生产消息后,主节点和从节点都收到消息并把消息都同时写入到本地后,才会回复消息。而异步复制是指,当主节点将数据保存到本地后,直接返回成功的消息,不关系从节点是否写入成功。因此通过比较,我们可以看出,异步复制效率比较高,而同步双写更具有高可用性,数据也变得更加可靠。

环境准备

  1. Apache RocketMQ4.6.0 安装包

    下载地址:https://rocketmq.apache.org/dowloading/releases/,目前有官方有7个大版本,我下载的最新版本 4.6.0

    4.6.x 对JRE版本要求(需要有Java运行环境):

    Client Broker NameServer
    >=1.6 >=1.8 >=1.8
  1. 2台Linux服务器

    主机 IP地址 角色 模式
    A机器 192.168.1.240 NameServer、broker-a-master、broker-b-slave Master/Slave
    B机器 192.168.1.241 NameServer、broker-b-master、broker-a-slave Master/Slave

3.分别A、B两台机器中下载解压RocketMQ文件(二进制包)

1
$ mkdir rocketmq && cd rocketmq
2
$ wget http://mirrors.tuna.tsinghua.edu.cn/apache/rocketmq/4.6.0/rocketmq-all-4.6.0-bin-release.zip
3
$ unzip rocketmq-all-4.6.0-bin-release.zip
4
$ mv rocketmq-all-4.6.0-bin-release 4.6.0
5
$ pwd
6
/home/data/application/rocketmq/4.6.0
7
$ ll
8
总用量 48
9
drwxr-xr-x 2 root root  4096 11月 20 11:04 benchmark
10
drwxr-xr-x 3 root root  4096 8月  19 15:31 bin
11
drwxr-xr-x 6 root root  4096 8月   6 16:23 conf
12
drwxr-xr-x 2 root root  4096 11月 20 11:04 lib
13
-rw-r--r-- 1 root root 17336 8月   6 16:23 LICENSE
14
-rw-r--r-- 1 root root  1338 8月   6 16:23 NOTICE
15
-rw-r--r-- 1 root root  4225 11月  1 16:54 README.md

集群配置

1.在A机器上配置MasterA/SlaveB

1
[root@A 2m-2s-async]# vim broker-a.properties
1
# 集群名称
2
brokerClusterName=rocketmq_cluster
3
brokerName=broker-a
4
# 主服务器必须为0
5
brokerId=0
6
deleteWhen=04
7
fileReservedTime=48
8
brokerRole=ASYNC_MASTER
9
flushDiskType=ASYNC_FLUSH
10
autoCreateTopicEnable=true
11
listenPort=10911
12
storePathRootDir=$ROCKETMQ_HOME/srote/a
13
# nameServer地址,分号分割
14
namesrvAddr=192.168.1.240:9876;192.168.1.241:9876
1
[root@A 2m-2s-async]# vim broker-b-s.properties
1
# 集群名称
2
brokerClusterName=rocketmq_cluster
3
brokerName=broker-b
4
# 从服务器大于0
5
brokerId=1
6
deleteWhen=04
7
fileReservedTime=48
8
brokerRole=ASYNC_MASTER
9
flushDiskType=ASYNC_FLUSH
10
autoCreateTopicEnable=true
11
listenPort=10950
12
storePathRootDir=$ROCKETMQ_HOME/srote/b
13
# nameServer地址,分号分割
14
namesrvAddr=192.168.1.240:9876;192.168.1.241:9876

2.在B机器上配置MasterB/SlaveA

1
[root@B 2m-2s-async]# vim broker-b.properties
1
# 集群名称
2
brokerClusterName=rocketmq_cluster
3
brokerName=broker-b
4
# 主服务器必须为0
5
brokerId=0
6
deleteWhen=04
7
fileReservedTime=48
8
brokerRole=ASYNC_MASTER
9
flushDiskType=ASYNC_FLUSH
10
autoCreateTopicEnable=true
11
listenPort=10950
12
storePathRootDir=$ROCKETMQ_HOME/srote/b
13
# nameServer地址,分号分割
14
namesrvAddr=192.168.1.240:9876;192.168.1.241:9876
1
[root@B 2m-2s-async]# vim broker-a-s.properties
1
# 集群名称
2
brokerClusterName=rocketmq_cluster
3
brokerName=broker-a
4
# 从服务器大于0
5
brokerId=1
6
deleteWhen=04
7
fileReservedTime=48
8
brokerRole=ASYNC_MASTER
9
flushDiskType=ASYNC_FLUSH
10
autoCreateTopicEnable=true
11
listenPort=10911
12
storePathRootDir=$ROCKETMQ_HOME/srote/a
13
# nameServer地址,分号分割
14
namesrvAddr=192.168.1.240:9876;192.168.1.241:9876

3.启动NameServer集群

1
### 在A机器启动 NameServer
2
[root@A 4.6.0]# nohup sh bin/mqnamesrv &
3
### 验证 NameServer 是否启动成功
4
[root@A 4.6.0]# tail -f nohup.out
5
The Name Server boot success...
6
7
### 在B机器启动 NameServer
8
[root@B 4.6.0]# nohup sh bin/mqnamesrv &
9
### 验证 NameServer 是否启动成功
10
[root@B 4.6.0]# tail -f nohup.out
11
The Name Server boot success...

P.S. 如果出现Cannot allocate memory 异常信息,则需要修改一下runserver.sh和runbroker.sh的合适的jvm参数就可以了。

4.启动Broker集群

  • 在A机器启动Broker
1
### 在A机器启动Master、Slave
2
[root@A 4.6.0]# nohup sh bin/mqbroker -c $ROCKETMQ_HOME/conf/2m-2s-async/broker-a.properties &
3
[root@A 4.6.0]# nohup sh bin/mqbroker -c $ROCKETMQ_HOME/conf/2m-2s-async/broker-b-s.properties &
  • 在B机器启动Broker
1
### 在B机器启动Master、Slave
2
[root@B 4.6.0]# nohup sh bin/mqbroker -c $ROCKETMQ_HOME/conf/2m-2s-async/broker-b.properties &
3
[root@B 4.6.0]# nohup sh bin/mqbroker -c $ROCKETMQ_HOME/conf/2m-2s-async/broker-a-s.properties &
  • $ROCKETMQ_HOME指的RocketMQ安装目录,需要用户自己设置此环境变量。

    1
    vim /etc/profile
    2
    ### 在尾部加上
    3
    export ROCKETMQ_HOME=/home/data/application/rocketmq/4.6.0
    4
    ### 重启环境生效
    5
    source /etc/profile

我在A机器启动Broker的时候出现了异常信息:

1
[main] ERROR RocketmqCommon - Failed to obtain the host name
2
java.net.UnknownHostException: testing: testing: 域名解析暂时失败
3
	at java.net.InetAddress.getLocalHost(InetAddress.java:1506) ~[na:1.8.0_221]
4
	at org.apache.rocketmq.common.BrokerConfig.localHostName(BrokerConfig.java:189) [rocketmq-common-4.6.0.jar:4.6.0]
5
	at org.apache.rocketmq.common.BrokerConfig.<init>(BrokerConfig.java:38) [rocketmq-common-4.6.0.jar:4.6.0]
6
	at org.apache.rocketmq.broker.BrokerStartup.createBrokerController(BrokerStartup.java:110) [rocketmq-broker-4.6.0.jar:4.6.0]
7
	at org.apache.rocketmq.broker.BrokerStartup.main(BrokerStartup.java:58) [rocketmq-broker-4.6.0.jar:4.6.0]
8
Caused by: java.net.UnknownHostException: testing: 域名解析暂时失败
9
	at java.net.Inet6AddressImpl.lookupAllHostAddr(Native Method) ~[na:1.8.0_221]
10
	at java.net.InetAddress$2.lookupAllHostAddr(InetAddress.java:929) ~[na:1.8.0_221]
11
	at java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1324) ~[na:1.8.0_221]
12
	at java.net.InetAddress.getLocalHost(InetAddress.java:1501) ~[na:1.8.0_221]
13
	... 4 common frames omitted

由错误信息得知,这是由于Broker启动的时候找不到主机名(我的主机名叫testing)对应的IP地址造成的。可以通过修改 /etc/hosts 文件,增加一个主机名解析就可以了。

1
$ echo '127.0.0.1 testing' >> /etc/hosts

当看到所以broker启动成功即完成。

broker.properties的详细配置信息:

1
#所属集群名字
2
brokerClusterName=rocketmq-cluster
3
#broker名字,注意此处不同的配置文件填写的不一样
4
brokerName=broker-a
5
#0表示Master,>0表示Slave
6
brokerId=0
7
#nameServer地址,分号分割
8
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
9
#在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
10
defaultTopicQueueNums=4
11
#是否允许Broker自动创建Topic,建议线下开启,线上关闭
12
autoCreateTopicEnable=true
13
#是否允许Broker自动创建订阅组,建议线下开启,线上关闭
14
autoCreateSubscriptionGroup=true
15
#Broker对外服务的监听端口
16
listenPort=10911
17
#删除文件时间点,默认凌晨4点
18
deleteWhen=04
19
#文件保留时间,默认48小时
20
fileReservedTime=120
21
#commitLog每个文件的大小默认1G
22
mapedFileSizeCommitLog=1073741824
23
#ConsumeQueue每个文件默认存30W条,根据业务情况调整
24
mapedFileSizeConsumeQueue=300000
25
#destroyMapedFileIntervalForcibly=120000
26
#redeleteHangedFileInterval=120000
27
#检测物理文件磁盘空间
28
diskMaxUsedSpaceRatio=88
29
#存储路径
30
storePathRootDir=/usr/local/rocketmq/store
31
#commitLog存储路径
32
storePathCommitLog=/usr/local/rocketmq/store/commitlog
33
#消费队列存储路径存储路径
34
storePathConsumeQueue=/usr/local/rocketmq/store/consumequeue
35
#消息索引存储路径
36
storePathIndex=/usr/local/rocketmq/store/index
37
#checkpoint文件存储路径
38
storeCheckpoint=/usr/local/rocketmq/store/checkpoint
39
#abort文件存储路径
40
abortFile=/usr/local/rocketmq/store/abort
41
#限制的消息大小
42
maxMessageSize=65536
43
#flushCommitLogLeastPages=4
44
#flushConsumeQueueLeastPages=2
45
#flushCommitLogThoroughInterval=10000
46
#flushConsumeQueueThoroughInterval=60000
47
#Broker的角色
48
#-ASYNC_MASTER异步复制Master
49
#-SYNC_MASTER同步双写Master
50
#-SLAVE
51
brokerRole=ASYNC_MASTER
52
#刷盘方式
53
#-ASYNC_FLUSH异步刷盘
54
#-SYNC_FLUSH同步刷盘
55
flushDiskType=ASYNC_FLUSH
56
#checkTransactionMessageEnable=false
57
#发消息线程池数量
58
#sendMessageThreadPoolNums=128
59
#拉消息线程池数量
60
#pullMessageThreadPoolNums=128

查看NameServer、Broker服务是否启动

1
$ jps
2
32515 BrokerStartup
3
32618 BrokerStartup
4
32764 Jps
5
31613 NamesrvStartup

关闭所有服务

1
$ sh bin/mqshutdown broker
2
$ sh bin/mqshutdown namesrv

安装管理面板(rocketmq-console-ng)

1.下载源代码编译

1
git clone https://github.com/apache/rocketmq-externals/tree/master/rocketmq-console

或者

1
wget https://codeload.github.com/apache/rocketmq-externals/zip/master -O rocketmq-externals.zip

然后进入 rocketmq-console 模块

2.修改部分参数并编译

1
$ vim src/main/resources/application.properties
1
rocketmq.config.namesrvAddr=192.168.1.240:9876;192.168.1.241:9876

3.使用maven编译打包并启动

1
$ mvn clean package -Dmaven.test.skip=true
2
$ java -jar target/rocketmq-console-ng-1.0.1.jar

使用mqadmin查看集群情况

1
$ export NAMESRV_ADDR="192.168.1.240:9876;192.168.5.241:9876"
2
$ sh mqadmin clusterlist -n 192.168.1.240:9876

遇到的问题及处理办法

https://github.com/apache/rocketmq/issues/504

https://github.com/apache/rocketmq/issues/568

https://github.com/Shellbye/Shellbye.github.io/issues/69

相关资料

https://rocketmq.apache.org

https://github.com/apache/rocketmq/tree/release-4.6.0/docs/cn

https://github.com/apache/rocketmq-spring

-EOF-