RocketMQ集群架构实战笔记一

这里缺少上下文环境铺垫,如果可以的话会尽量补上,就是一些学习及实战的记录,所以看得人可能需要一些mq的基础才行。

NameServer

1、为了高可用,NameServer一般都会采用集群部署,NameServer的设计采用的是Peer-to-Peer的模式来做的,里面任何一台机器都是独立运行的,每个NameServer都有完整的集群路由信息,所以只要任何一台NameServer存活下来,就可以保证MQ系统正常运行。

2、每个Broker启动都会向所有的NameServer进行注册,然后保持一个基于TCP的长连接进行通信。

3、生产者和消费者每隔一段时间到NameServer去拉取一次最新的Broker集群信息

4、Broker每隔30s给所有的NameServer发送心跳,告诉每个NameServer自己目前还活着,这就是NameServer跟Broker之间的。每次NameServer收到一个Broker的心跳,就更新一下它的最近一次心跳时间,然后NameServer会每隔10s运行一个任务,去检查一下各个Broker的最近一次心跳时间,如果某个Broker超过120s都没发送心跳了,那么就认为这个Broker已经挂掉了。

Broker

1、Master Broker如何将消息同步给Slave Broker
为了保证MQ的数据不丢失,而且具备一定的高可用性,一般都是将Broker部署成Master-Slave模式,也就是一个Master Broker对应一个Slave Broker,然后Master需要在接收到消息之后,将数据同步给Slave,这样一旦Master Broker挂了,Slave上还有一份数据。
那么Master Broker上的数据是如何同步给Slave Broker的?其实是Slave Broker不停的发送请求到Master Broker去拉取消息的。

2、消息的读写
消费者获取的消息是从Master Broker获取还是从Slave Broker获取?答案是:有可能从Master Broker获取消息,也有可能从Slave Broker获取消息。消费者在获取消息的时候会先发送请求到Master Broker上去,请求获取消息,此时Master Broker会返回消息给消费者,同时在返回消息的时候会根据当时Master Broker的负载情况和Slave Broker的同步情况,向消费者建议下一次拉取消息的时候是从Master Broker拉取还是从Slave Broker拉取。

举个例子,假如Master Broker负载很重,比如要抗住10万写并发,你还从它这里拉取消息,给它加重负担,那肯定是不合适的,所以此时Master Broker就会建议你从Slave Broker去拉取消息。但是,如果Slave Broker同步太慢,跟不上消费,那就只能从Master Broker获取消息。如果是写入消息的话,那就只能从Master Broker写入。

3、如果Master Broker挂掉了怎么办
这个时候对读写都会有影响,首先Slave Broker可能没有来得及获取Master Broker上的最新数据,可能导致数据丢失。然后Slave Broker也不能自动切换为Master Broker。在RocketMQ4.5版本之前,都是用这种模式,一旦Master Broker挂了,就得手动做一些运维操作,把Slave Broker重新配置,重启服务升级为Master Broker,这就有点麻烦,可用性也不高。

4、基于dledger实现RocketMQ高可用自动切换
在RocketMQ4.5版本之后,这种情况得到了改变,因为RocketMQ支持了一种新的机制,叫做Dledger,是基于Raft协议实现的一个机制。简单来说,就是一个Master Broker对应多个副本,一旦Master Broker挂了,通过Dledger技术和Raft协议算法进行leader选举,直接将一个Slave Broker选举为新的Master Broker,然后这个新的Master Broker就可以对外提供服务了。

5、Topic
Topic翻译成中文就是主题的意思,但是这个翻译让人感觉有点懵,不好理解,其实它表达的意思是一个数据集合的概念。如果要往MQ里写消息,首先得创建Topic,作为数据集合存放消息,不同的消息类型应该创建不同的Topic去存放。

那么Topic是怎么存储在Broker集群里的呢?首先我们的数据量很大,所以不太可能存放在一台机器上。这里就体现出来一个的概念了。所以我们在创建Topic的时候可以指定让它里面的数据分散存储在多台Broker机器上。另外,每个Broker在和NameServer进行定时的心跳通信的时候,会告诉NameServer自己当前的数据情况,比如有哪些Topic的哪些数据在自己这里,这些信息都是属于路由信息的一部分。

6、生产者如何向Broker发送消息
生产者会和NameServer建立一个TCP长连接,定时从它那里拉取最新的路由信息,然后生产者就可以通过路由信息找到自己要投递消息的Topic分布在哪几台Broker上,此时根据负载均衡算法,从里面选择一台Broker机器出来,通过TCP和Broker建立一个长连接,然后通过这个长连接向Broker发送消息。这里要注意一点,那就是消息一定是投递到Master Broker的,然后再同步给Slave Broker。

8、消费者如何从Broker拉取消息
消费者也是会和NameServer建立长连接,然后拉取路由信息,接着找到自己要获取消息的Topic在哪几台Broker上,就可以跟Broker建立长连接,从里面拉取消息了。

集群架构部署

1、安装包下载
直接到官网去下载就行了,这里就不再演示,下面给出路径
http://rocketmq.apache.org/dowloading/releases/

2、机器准备
服务器1-主:10.200.16.1,安装的服务:DLedger,Broker,NameServer
服务器2-从:10.200.16.2,安装的服务:DLedger,Broker,NameServer
服务器3-从:10.200.16.3,安装的服务:DLedger,Broker,NameServer

3、文件配置
这里要说一下,第一个Broker的配置文件是broker-n0.conf,第二个Broker的配置文件是broker-n1.conf,第三个Broker的配置文件是broker-n2.conf,broker-n0.conf配置内容如下:

## 集群名
brokerClusterName = RaftCluster
## broker组名,同一个RaftClusterGroup内,brokerName名要一样
brokerName=RaftNode00
## 监听的端口,可以考虑三台机器使用同样的端口
listenPort=30911
## 你设置的NameServer地址和端口
namesrvAddr=10.200.16.1:9876;10.200.16.2:9876;10.200.16.3:9876
#主题不存在时是否自动创建主题
autoCreateTopicEnable=false

#订阅组不存在时是否自动创建订阅组
autoCreateSubscriptionGroup=false

#数据存储根路径
storePathRootDir=/tmp/rmqstore/node00

#commitlog数据存储根路径
storePathCommitLog=/tmp/rmqstore/node00/commitlog

#是否启用DLeger集群模式
enableDLegerCommitLog=true

#与brokerName保持一致就好
dLegerGroup=RaftNode00
## n0 n1 n2 分别是broker1,broker2,broker3 的 dLegerSelfId
## 例如:dLegerPeers=n0-服务器1的IP:40911;n1-服务器2的IP:40912;n2-服务器3的IP:40913
##三台机器必须配置成一样的
dLegerPeers=n0-10.200.16.1:40911;n1-10.200.16.2:40912;n2-10.200.16.3:40913
## must be unique
## 这个值必须是在同一个RaftClusterGroup内唯一的
dLegerSelfId=n0
#服务端处理消息发送线程池数量,一般建议配置成和CPU核数一样
sendMessageThreadPoolNums=16
## 由于我的虚拟机配置了多个网卡,所以会绑定ip错误,因此我配置了这项,
brokerIP1=10.200.16.1

broker-n1.conf配置内容如下:

## 集群名
brokerClusterName = RaftCluster

## broker组名,同一个RaftClusterGroup内,brokerName名要一样
brokerName=RaftNode00

## 监听的端口
listenPort=30921

## 你设置的NameServer地址和端口
namesrvAddr=10.200.16.1:9876;10.200.16.2:9876;10.200.16.3:9876

#主题不存在时是否自动创建主题
autoCreateTopicEnable=false

#订阅组不存在时是否自动创建订阅组
autoCreateSubscriptionGroup=false

#数据存储根路径
storePathRootDir=/tmp/rmqstore/node01

#commitlog数据存储根路径
storePathCommitLog=/tmp/rmqstore/node01/commitlog

#是否启用DLeger集群模式
enableDLegerCommitLog=true

#与brokerName保持一致就好
dLegerGroup=RaftNode00

## n0 n1 n2 分别是broker1,broker2,broker3 的 dLegerSelfId
## 例如:dLegerPeers=n0-服务器1的IP:40911;n1-服务器2的IP:40912;n2-服务器3的IP:40913
dLegerPeers=n0-10.200.16.1:40911;n1-10.200.16.2:40912;n2-10.200.16.3:40913

## must be unique,broker在组里的id
dLegerSelfId=n1

#服务端处理消息发送线程池数量,一般建议配置成和CPU核数一样
sendMessageThreadPoolNums=16

brokerIP1=10.200.16.2

broker-n2.conf的配置和broker-n1.conf的配置一样,所以这里就不再赘述了。

4、启动集群

nohup sh bin/mqnamesrv > nohubNameserv &
nohup sh bin/mqbroker  > nohubBroker -c conf/dledger/broker-n0.conf &

nohup sh bin/mqnamesrv > nohubNameserv &
nohup sh bin/mqbroker  > nohubBroker -c conf/dledger/broker-n1.conf &

nohup sh bin/mqnamesrv > nohubNameserv &
nohup sh bin/mqbroker  > nohubBroker -c conf/dledger/broker-n2.conf &

5、查看集群情况

[root@localhost rocketmq-4.7.1]# sh bin/mqadmin clusterList -n 127.0.0.1:9876
RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).
RocketMQLog:WARN Please initialize the logger system properly.
#Cluster Name     #Broker Name            #BID  #Addr                  #Version                #InTPS(LOAD)       #OutTPS(LOAD) #PCWait(ms) #Hour #SPACE
RaftCluster       RaftNode00              0     10.200.16.1:30911   V4_7_1                   0.00(0,0ms)         0.00(0,0ms)          0 442545.08 -1.0000
RaftCluster       RaftNode00              2     10.200.16.2:30921   V4_7_1                   0.00(0,0ms)         0.00(0,0ms)          0 442545.08 -1.0000
RaftCluster       RaftNode00              3     10.200.16.3:30931   V4_7_1                   0.00(0,0ms)         0.00(0,0ms)          0 442545.08 -1.0000

6、启动内存不够
修改 bin/runbroker.sh 和 bin/runserver.sh 中的

//将参数调低
JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g -Xmn4g

7、报连接超时
查看防火墙服务状态 systemctl status firewalld

将防火墙关闭 systemctl stop firewalld

8、控制台

  • 在github上下载源码,访问地址:https://github.com/apache/rocketmq-externals
  • 上传压缩包到虚拟机,解压压缩包,修改rocketmq-console配置文件,添加namesrv地址
vim /home/rocketmq-externals-master/rocketmq-console/src/main/resources/application.properties

#在此参数中添加前面两个虚拟机中启动的namesrv地址
rocketmq.config.namesrvAddr=10.200.16.1:9876;10.200.16.2:9876;10.200.16.3:9876
  • 切换到rocketmq-console目录
mvn clean package -Dmaven.test.skip=true
  • 在home目录下新建一个文件夹rocketmq-console,之后将编译打包成功后的jar包copy到该文件夹下
mkdir /home/rocketmq-console
cp /home/rocketmq-externals-master/rocketmq-console/target/rocketmq-console-ng-1.0.1.jar /home/rocketmq-console
  • 切换到rocketmq-console目录下,新建一个启动脚本,添加以下内容
cd /home/rocketmq-console
vim start.sh

nohup java -jar /home/rocketmq-console/rocketmq-console-ng-1.0.1.jar > /home/rocketmq-console/rocketmq-console.log 2>&1 &
echo $! > /home/rocketmq-console/project.pid
  • 通过脚本启动rocketmq-console
sh start.sh

你可能感兴趣的:(RocketMQ集群架构实战笔记一)