K8S Docker搭建RocketMQ Dledger高可用集群

本篇文章回顾在华润基于K8S和Docker云设施搭建初步高可用具备failover的RocketMQ集群。RocketMQ版本是5.0.0。

目前现状

采用Dledger模式部署集群,3台namesrv,3台broker,namesrv每台1g的Docker部署,broker每台2g的Docker部署。测试以及生产实践在master发生故障或掉线时,broker集群可以选主出新的master。

RocketMQ集群的几种模式

首先我们看有几种集群的部署模式。官网文档对于模式这块的部署讲述的有点模糊,特别对dledger和controller模式之间的关系基本上没有讲,都是靠网上自己学习资料思考去理解。我说下我的理解,基本上就是以下3种模式。

master-slave模式

其中master-slave是最基本的集群,可以单master,多master,多master-slave,这样提供了水平扩展能力,解决高TPS和高QPS的能力。但是最主要缺陷是master挂了,slave没办法接替其角色继续写入消息,只能给consumer提供消费消息能力,相当于3master的集群,现在变成2master的负载能力。

Dledger模式

那么在此基础上增加了Dledger模式,就是让master-slave组具备自动failover的能力。这个模式会在broker之间建立通信,通过raft协议选出master剩余2个broker节点为其slave。master通过配置可以同步或异步地向slave发送消息。在master宕机后自动选出一个新master。因为基于raft协议所以最低需要3个节点才能进行failover的选主过程,在只有2个节点时不能完成此过程。

controller模式

controller模式是rmq在5.0版本后新推出的一种高可用集群模式。DLedger(Raft)能力从原本的复制链路上移到controller,将选主切换能力上移,单独作为一个选主组件。RIP-44提出增加一个DLedgerControlller的选主组件,它是可选部署的,在无切换架构的基础上,部署后经过配置就可以拥有切换的能力,它可以内嵌在Nameserver中,也可以独立部署。如果内嵌在NameServer中,NameServer本身的能力还是无状态的,比如有三个NameServer都内嵌部署了DLedger Controller,如果宕机两个节点,NameServer仍然存在一个可以提供路由服务,DLedger Controller宕机两个节点后由于达不到Raft多数派的要求无法再协助Broker切换,但是消息集群本身正常的收发服务不会受到影响。

RocketMQ Dledger集群搭建方案

最终在部署模式上我选择了Dledger模式部署。相对master-slave组有failover能力。相对controller模式部署更简单。

编写broker配置

首先需要编写broker配置文件。我们需要修改conf/dledger/broker.conf配置文件。将这份文件copy3份出来,命名为broker0.conf、broker1.conf、broker2.conf。这3份broker文件基本都一致,brokerRole都配置为master,让其自主选出master。只是在brokerIP、dLegerSelfId上有不同。

# 所属集群名称
brokerClusterName = CpmsCluster
#broker名称,master和slave使用相同的名称,表明他们的主从关系
brokerName = brokerA
#表示几点做消息删除动作,默认是凌晨4点
deleteWhen = 04
#在磁盘上保留消息的时长,单位是小时
fileReservedTime = 48
# 这里的ip是此broker部署的节点IP,因为是K8S上部署,所以是一个内网可以解析为IP的工作负载名称
brokerIP1 = rmq-brokerA0
# namesrv也是K8S上内网工作负载
namesrvAddr=rmq-nameserv0:9876;rmq-nameserv1:9876;rmq-nameserv2:9876
#Broker 对外服务的监听端口
listenPort = 30911
# 配置为一个异步复制的master
brokerRole=ASYNC_MASTER
# 消息同步刷盘
flushDiskType=SYNC_FLUSH

#存储路径
storePathRootDir=/rmq/store
#commitLog存储路径
storePathCommitLog=/rmq/store/commitlog
#消费队列存储路径
storePathConsumeQueue=/rmq/store/consumequeue
#索引存储路径
storePathIndex=/rmq/store/index
#checkpoint文件存储路径
storeCheckpoint=/rmq/store/checkpoint
#abort文件存储路径
abortFile=/rmq/store/abort

# 开启Dledger集群
enableDLegerCommitLog=true
# DLedger Raft Group的名字,建议和 brokerName 保持一致
dLegerGroup=brokerA
# 集群内所有broker节点的IP
dLegerPeers=n0-rmq-brokerA0:40911;n1-rmq-brokerA1:40912;n2-rmq-brokerA2:40913
# 节点 id, 必须属于 dLegerPeers 中的一个;同 Group 内各个节点要唯一
dLegerSelfId=n0
# 发送线程个数,建议配置成 Cpu 核数
sendMessageThreadPoolNums=4

编写dockerfile

在3份broker配置准备好后,就可以编写打包namesrv和broker的dockerfile了。这需要一些dockerfile知识。首先编写namesrv。

# 这里指定镜像的适用平台和基础镜像
FROM --platform=linux/amd64 openjdk:8-jdk-alpine3.9

# 容器中建一个目录
RUN mkdir -p /rmq
# 将当前工作目录定到opt
WORKDIR /rmq
# 把宿主机Dockerfile下的文件拷贝到容器/opt/rocketmq
COPY . /rmq
RUN mkdir -p /rmq/logs
RUN echo "Asia/Shanghai" > /etc/timezone

CMD nohup sh ./bin/mqnamesrv

我这里是直接准备好3份dockerfile以方便打包3个broker镜像。有了3个broker镜像,我直接在K8S上部署这3个工作负载就行嘞。这3个dockerfile都基本一致,只不过在最后CMD启动时传的分别是broker-n0.conf,n1,n2等文件。

FROM --platform=linux/amd64 openjdk:8-jdk-alpine3.9

# 容器中建一个目录
RUN mkdir -p /rmq
# 将当前工作目录定到opt
WORKDIR /rmq
# 把宿主机Dockerfile下的文件拷贝到容器/rmq
COPY . /rmq
RUN mkdir -p /rmq/logs
RUN echo "Asia/Shanghai" > /etc/timezone

# 将容器中指定目录挂载到宿主机匿名卷(没有指定宿主机的指定目录就是匿名卷)。双方目录不存在都会自动创建,且目录下的所有文件都持久化
VOLUME ["/rmq/store","/rmq/logs"]
# ${}取环境变量,可以在docker run -e传入
CMD sh /rmq/bin/mqbroker -c conf/dledger/broker-n0.conf

打包镜像上华润云

现在我们准备好了broker配置和dockerfile,根据线上宿主机的实际配置要调整下namesrv和broker的内存大小(部门预算有限,要省着点花)。

修改runserver.sh的jvm内存参数,调整到合适的大小,估计1g就够了

JAVA_OPT="${JAVA_OPT} -server -Xms1g -Xmx1g -Xmn512m -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=128m"

修改runbroker.sh的jvm内存参数

JAVA_OPT="${JAVA_OPT} -server -Xms2g -Xmx2g -Xmn1g" JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=10 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0"

然后把3个broker镜像和namesrv镜像打包出来了。在K8S中建立3个broker0、1、2的工作负载,namesrv工作负载。

踩得坑

对于broker和namesrv要在K8S上建工作负载时开放指定的端口,否则集群会无法互相通信。其中nameserv要开的端口有:9876。broker在集群模式下端口比较奇怪,listenPort是配置文件中指定的,如30911,还有集群内节点通信的端口40911。此外还有一个端口30909。这个端口不知道干嘛的,但是看其它两个broker的端口分别是30919、30929。好像是各自broker的listenPort-2。所以也都开放了。不开放的话,rmq-dashboard在连接broker时会报错提示。

压测和上线情况

压测方法

  • 编写生产者&消费者程序,多线程并发地发送消息给MQ,同时消费者消费消息。指定并发线程数和消息总数。完整的走了一遍发送消息->存储消息->消费消息的链路。更贴近真实线上业务场景。
  • 官方自带的压测脚本,省去自己编写脚本的工作,走了一遍发送消息->存储消息链路。

目前我们主要对broker集群存储消息的性能做测试,所以选择了第2种方法更加省时省力测试。

 压测场景

并发线程10,50万消息,每个消息512字节

从监控master所在201机器上看CPU、内存、磁盘IO、带宽,基本都处于较低资源使用水平。cpu不到30%,内存基本无变化,磁盘IOPS在400,都比较健康。TPS达到1700左右,最大RT246ms,50万消息10个线程并发耗时2分30秒发送完毕。

并发线程20,100万消息,512字节

cpu使用率比并发10稍高,峰值50%左右。内存平稳。iops稳定600左右。

gc情况良好,没有fgc,基本对象在ygc回收完毕。但是年轻代随着并发量增加,内存使用增加的比并发10要快很多,ygc频率增加,但是每次ygc时间很短。 

并发线程数增加后,吞吐量也增加,还没到拐点。TPS 5700,最大RT 360ms,平均 4ms。3分钟发完。

经过以上压测得出压测报告,TPS达到近6000的消息发送,且最大RT360ms,(实际业务中因为producer发消息给broker,有网络IO,所以这个TPS和RT会高一点)完全可以应付我们的日常业务需求。因此我们只用了3台namesrv每个实例1G,3台broker每个实例2G,小成本机器就搭建了一套初步高可用的线上MQ集群。 目前这套集群在华润万象生活的业务生产中每天收发100万左右的消息,集群状态平稳。

### 回答1: 要搭建RocketMQ集群,可以使用Docker容器化技术来实现。以下是搭建RocketMQ集群的步骤: 1. 安装DockerDocker Compose 2. 创建一个Docker Compose文件,定义RocketMQ集群的配置和服务 3. 在Docker Compose文件中定义三个服务:NameServer、Broker和Console 4. 配置NameServer服务,指定NameServer的端口和集群名称 5. 配置Broker服务,指定Broker的端口、NameServer地址和集群名称 6. 配置Console服务,指定Console的端口和NameServer地址 7. 启动Docker Compose,创建RocketMQ集群 8. 使用RocketMQ Console管理和监控集群 以上是搭建RocketMQ集群的基本步骤,具体的实现细节可以参考RocketMQ官方文档和Docker官方文档。 ### 回答2: RocketMQ是一个 Apache 开源的分布式消息传递系统,在分布式应用中广泛应用。它具有高可用性、高并发性、高性能、可扩展性等优点。Docker 是一种容器化技术,它可以将应用程序及其依赖项打包成一个 Docker 容器,从而使应用程序在运行时具有一致的环境。这就为 RocketMQ 集群搭建提供了很大的便利。这里我们就以 Docker 为基础,来讲解如何搭建 RocketMQ 集群。 第一步,创建 Dockerfile 我们首先需要创建 Dockerfile,该文件用于指导 Docker 构建 RocketMQ 集群。以下是 Dockerfile 内容: FROM java:8-jre ENV ROCKETMQ_VERSION=4.3.2 ENV ROCKETMQ_HOME=/opt/rocketmq-${ROCKETMQ_VERSION} ADD rocketmq-all-${ROCKETMQ_VERSION}-bin-release.tar.gz /opt RUN ln -s ${ROCKETMQ_HOME}/bin/mqnamesrv /usr/local/bin && ln -s ${ROCKETMQ_HOME}/bin/mqbroker /usr/local/bin CMD cd ${ROCKETMQ_HOME}/bin && nohup sh mqnamesrv & CMD cd ${ROCKETMQ_HOME}/bin && sleep 5 && sh mqbroker -n namesrv:9876 autoCreateTopicEnable=true 第二步,构建 Docker image 我们使用以下命令构建 Docker image: $ docker build -t rocketmq:4.3.2 . 第三步,运行容器 接下来在一台机器上启动该镜像的多个容器,每个容器都要有一个不同的名字和 IP 地址,这样它们之间才能通信。RocketMQ 集群需要两个组件:NameServer 和 Broker。 启动 NameServer 容器: $ docker run --name rmqnamesrv -p 9876:9876 -d rocketmq:4.3.2 sh mqnamesrv 启动 Broker 容器: $ docker run --name rmqbroker -p 10911:10911 -p 10909:10909 \ -e "NAMESRV_ADDR=192.168.1.100:9876;192.168.1.101:9876" \ -e "JAVA_OPTS=-Duser.home=/opt" \ --link rmqnamesrv:namesrv \ -d rocketmq:4.3.2 -e "NAMESRV_ADDR" 用于指定 NameServer 的地址,并以分号分隔;-e "JAVA_OPTS" 用于指定 JAVA_HOME 路径。 第四步,测试 RocketMQ 集群 我们可以使用以下命令测试该 RocketMQ 集群是否正常: $ docker exec -it rmqbroker sh mqadmin clusterList -n namesrv:9876 输出如下: Cluster Name: DefaultCluster Cluster Status: OK 至此,我们成功搭建RocketMQ 集群RocketMQ 集群搭建十分简单,只需按照上述步骤操作即可。对于生产环境,需要更加细致地考虑配置和优化。 ### 回答3: RocketMQ是一款开源的分布式消息中间件,它使用广泛且可靠,尤其是应用在高并发场景下。而Docker则是现在非常火热的容器化技术,它可以轻松的实现RocketMQ集群部署。下面,我们将介绍如何使用Docker搭建RocketMQ集群。 首先要做的是创建一个Docker容器并安装RocketMQ,容器可以复制多个并形成集群。在这个过程中,我们可以使用开源的RocketMQ容器来作为我们的基础镜像。我们可以使用docker pull指令从docker hub拉取RocketMQ官方镜像,然后运行docker run命令将容器启动起来。启动容器时,需要指定一些参数以方便配置RocketMQ。例如: docker run -d --name rmqnamesrv --restart=always -p 9876:9876 -v /mnt/docker/namesrv/logs:/root/logs -e "MAX_POSSIBLE_HEAP=100000000" -e "JAVA_OPT_EXT=-server -Xms512m -Xmx512m -Xmn256m" rocketmqinc/rocketmq:4.3.2 sh mqnamesrv 该命令意味着我们正在创建一个名为rmqnamesrv的容器,并将容器的5672端口映射到宿主机的5672端口,还为容器设置了一个存储卷用于存储RocketMQ的日志,以及设置了Java运行参数等。 类似于namesrv容器,我们还可以使用该命令创建broker容器,以实现RocketMQ集群,我们可以在同一台主机上启动多个容器,也可以在多台主机上启动多个容器,并连接它们的端口,从而实现分布式部署模式。 接下来,我们需要进行配置操作,通过修改配置文件来允许程序在集群环境中工作。例如修改broker的配置文件broker.conf,配置完后需要将该文件映射到相关容器中,以使配置生效。 最后,我们需要将Docker配置成依据我们指定的规则,在多个容器之间启动和停止,从而使整个集群能够随时运行和维护。这意味着我们需要创建脚本和服务来管理容器的启动和停止,并处理容器之间的通信,以此表现Docker的自动化管理。这可以通过Docker Compose来实现,该工具使我们能够启动和停止多个容器,并将它们组织成服务。 总之,通过使用Docker搭建RocketMQ集群,使得我们不必关心繁琐的安装和配置过程,它简化了部署,增强了系统的可维护性和可扩展性。当然,要加强对DockerRocketMQ的学习,熟悉更多命令和配置以适应不同场景下的构建。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值