前言

本文介绍如何使用DLedger搭建RocketMQ集群,并实现数据的高可用和负载均衡。主要包括搭建DLedger集群、配置RocketMQ Broker以使用DLedger作为存储、创建Topic等步骤。

什么是RocketMQ-DLedger集群

  • 引用官方说法如下:

RocketMQ-on-DLedger Group 是指一组相同名称的 Broker,至少需要 3 个节点,通过 Raft 自动选举出一个 Leader,其余节点 作为 Follower,并在 Leader 和 Follower 之间复制数据以保证高可用。
RocketMQ-on-DLedger Group 能自动容灾切换,并保证数据一致。
RocketMQ-on-DLedger Group 是可以水平扩展的,也即可以部署任意多个 RocketMQ-on-DLedger Group 同时对外提供服务。

  • 根据网上搜索的资料,之前官方的集群方案(主从方案)一旦主节点挂掉,那么需要手动将Slave节点改为Master节点并重新启动,才能恢复。而DLedger集群可以通过自动选举的方式选举出Master节点,当任意一个Master挂掉之后,程序会自动选举新的Master替换为主节点。

PS:同一组RocketMQ-Dledger集群至少需要3个节点,如果只有2个节点,当Master节点挂掉后,由于得不到过半选票,Slave节点不会切换为Master节点。

同一个集群可部署多个 Broker,同时提供服务。

宿主机搭建

参考官方文档,写的很详细,包括如何将旧机群转换为新集群。此处不再描述。

Docker容器搭建

  • 使用Docker环境搭建,有个坑,如果采用默认的Bridge网络模式,搭建完成后可能会出现集群异常,报org.apache.rocketmq.remoting.exception.RemotingConnectException: connect to <172.17.0.11:10911> failed异常,控制台无法连接RocketMQ节点问题。

    此处猜测为采用bridge网络后,broker内会使用容器内部IP,导致使用到内部IP无法正常连接。具体如下图

image-20210908175102922

image-20210908173401657

因此,我采用了host模式进行搭建,直接共享宿主机网卡。如有其他搭建方式欢迎分享出来一起学习~

方式一

准备工作

  1. 官方Release下载二进制文件,如rocketmq-all-4.9.1.zip

  2. 解压文件,在conf/dledger/文件夹下找到三个配置文件,分别为broker-n0.confbroker-n1.confbroker-n2.conf

  3. 修改配置文件

    • namesrvAddr:修改成nameserver地址,如172.16.0.4:9876;172.16.0.17:9876;172.16.0.14:9876
    • storePathRootDir:根据实际需要修改为存储路径地址
    • storePathCommitLog:根据实际需要改成commitlog存储路径地址
    • enableDLegerCommitLog:是否启动 DLedger,填true
    • dLegerPeers:各节点端口信息,如n0-127.0.0.1:40911;n1-127.0.0.1:40912;n2-127.0.0.1:40913
    • sendMessageThreadPoolNums:发送线程个数,建议配置成 CPI 核数,4核填4,8核填8,以此类推
    • dLegerSelfId:节点 id,同一个Group中必须唯一
    brokerClusterName = RaftCluster
    brokerName=RaftNode00
    #listenPort=30911
    namesrvAddr=127.0.0.1:9876
    storePathRootDir=/tmp/rmqstore/node00
    storePathCommitLog=/tmp/rmqstore/node00/commitlog
    enableDLegerCommitLog=true
    dLegerGroup=RaftNode00
    dLegerPeers=n0-127.0.0.1:40911;n1-127.0.0.1:40912;n2-127.0.0.1:40913
    ## must be unique
    dLegerSelfId=n0
    sendMessageThreadPoolNums=16
    
  4. 假设我现在有三台机器,内网IP分别为:

    172.16.0.4,172.16.0.17,172.16.0.14

    则对应的配置文件为:

    brokerClusterName = RaftCluster
    brokerName=RaftNode00
    #listenPort=30911
    namesrvAddr=172.16.0.4:9876;172.16.0.17:9876;172.16.0.14:9876
    storePathRootDir=/opt/data/
    storePathCommitLog=/opt/data/commitlog
    enableDLegerCommitLog=true
    dLegerGroup=RaftNode00
    dLegerPeers=n0-172.16.0.4:40911;n1-172.16.0.17:40911;n2-172.16.0.14:40911
    ## must be unique
    dLegerSelfId=n0
    sendMessageThreadPoolNums=4
    

    PS:除了dLegerSelfId需要调整,其他节点配置都一样。

启动容器

  • 启动带有JDK环境的容器镜像,通过解压安装包后手动执行启动脚本的方式启动

    需提前将解压并修改配置文件后的rocketmq-4.9.1文件夹分别传到3台服务器上。

    cname="rocketmq-node1"
    logs="/opt/data/"${cname}
    
    docker run -d --privileged=true --restart=always -v /opt/script/setup/rocketmq-node1/rocketmq-4.9.1/:/usr/local/rocketmq-4.9.1/ --net=host --name ${cname} -v ${logs}:/opt/data 10.252.0.29:5000/base/jdk:v19.01.01
    

启动NameServer

进入docker容器,进入RocketMQ文件夹的bin目录下,执行以下命令

nohup ./mqnamesrv > /opt/data/namesrv.log 2>&1 &

/opt/data/namesrv.log为后台运行的日志路径

根据实际情况,可以启动多个NameServer做高可用

启动Broker

进入docker容器,进入RocketMQ文件夹的bin目录下,执行以下命令

节点1:

nohup sh mqbroker -c /usr/local/rocketmq-4.9.1/conf/dledger/broker-n0.conf > /opt/data/broker.log 2>&1 &

节点2:

nohup sh mqbroker -c /usr/local/rocketmq-4.9.1/conf/dledger/broker-n1.conf > /opt/data/broker.log 2>&1 &

节点3:

nohup sh mqbroker -c /usr/local/rocketmq-4.9.1/conf/dledger/broker-n2.conf > /opt/data/broker.log 2>&1 &

/opt/data/broker.log为后台运行的日志路径

  • 可通过修改bin目录下的runbroker.sh文件,调整启动占用的内存大小!

image-20210908180917133

方式二

准备工作

  • 打包rocketmq镜像

    1. rocketmq-docker的GitHub地址克隆docker脚本

    2. 执行以下命令开始制作docker镜像

      cd image-build
      sh build-image.sh RMQ-VERSION BASE-IMAGE
      

      RMQ-VERSION可以在官方查看

      BASE-IMAGE可以为centos或alpine

      例子:sh build-image.sh 4.9.2 centos

    3. 制作成功后会获得如下镜像:apacherocketmq/rocketmq:4.9.2

      image-20220210083929565

  • 打包rockermq-dashboard镜像

    前提:依赖上面拉取的docker脚本

    cd image-build
    sh build-image-dashboard.sh VERSION centos
    

    VERSION可以在官方查看

    例子:sh build-image-dashboard.sh 1.0.0 centos

    成功后获得如下镜像:apache/rocketmq-dashboard:1.0.0-centos

    image-20220210095523594

  • 准备broker配置文件

    1. 在三台机器分别创建以下目录

      • 创建Broker持久化目录

        mkdir -p /opt/data/rocketmq-{n}/broker/conf
        mkdir -p /opt/data/rocketmq-{n}/broker/logs
        mkdir -p /opt/data/rocketmq-{n}/broker/store
        
      • 创建NameServer持久化目录

        mkdir -p /opt/data/rocketmq-{n}/nameserver/logs
        

      {n}填写第n个节点的数字,如:mkdir -p /opt/data/rocketmq-01/broker/conf

      也可以不需要,根据自己需求决定

    2. 创建配置文件

      • 节点1

        vim /opt/data/rocketmq-01/broker/conf
        

        写入以下内容

        brokerIP1=172.16.32.73
        listenPort=30911
        brokerClusterName=RaftCluster
        brokerName=RaftNode00
        namesrvAddr=172.16.32.73:9876;172.16.32.54:9876;172.16.32.86:9876
        ## DLeger
        dLegerSelfId=n0
        dLegerGroup=RaftNode00
        enableDLegerCommitLog=true
        ## must be unique
        dLegerPeers=n0-172.16.32.73:40911;n1-172.16.32.54:40911;n2-172.16.32.86:40911
        sendMessageThreadPoolNums=4
        
      • 节点2

        vim /opt/data/rocketmq-02/broker/conf
        

        写入以下内容

        brokerIP1=172.16.32.54
        listenPort=30911
        brokerClusterName=RaftCluster
        brokerName=RaftNode00
        namesrvAddr=172.16.32.73:9876;172.16.32.54:9876;172.16.32.86:9876
        ## DLeger
        dLegerSelfId=n1
        dLegerGroup=RaftNode00
        enableDLegerCommitLog=true
        ## must be unique
        dLegerPeers=n0-172.16.32.73:40911;n1-172.16.32.54:40911;n2-172.16.32.86:40911
        
      • 节点3

        vim /opt/data/rocketmq-03/broker/conf
        

        写入以下内容

        brokerIP1=172.16.32.86
        listenPort=30911
        brokerClusterName=RaftCluster
        brokerName=RaftNode00
        namesrvAddr=172.16.32.73:9876;172.16.32.54:9876;172.16.32.86:9876
        ## DLeger
        dLegerSelfId=n2
        dLegerGroup=RaftNode00
        enableDLegerCommitLog=true
        ## must be unique
        dLegerPeers=n0-172.16.32.73:40911;n1-172.16.32.54:40911;n2-172.16.32.86:40911
        sendMessageThreadPoolNums=4
        

      主要是brokerIP1和dLegerSelfId的配置区别

  • 更改目录归属组与用户容器的配置一致

    在3台机器上执行下面的命令创建组和用户

    ## 创建组
    groupadd rocketmq
    ## 增加用户并加入组
    useradd -g rocketmq rocketmq
    ## 设置用户密码
    passwd rocketmq
    ## 更改组的 gid
    groupmod -g 3000 rocketmq
    ## 更改用户的 uid
    usermod -u 3000 rocketmq
    ## 查看是否更改成功
    id rocketmq
    

    在3台机器上分别更改上面创建的目录权限为rocketmq

    ## 节点1
    chown -R rocketmq:rocketmq /opt/data/rocketmq-01
    ## 节点2
    chown -R rocketmq:rocketmq /opt/data/rocketmq-02
    ## 节点3
    chown -R rocketmq:rocketmq /opt/data/rocketmq-03
    

启动NameServer

  • 节点1

    docker run -itd --name rocketmq-nameserver-01 --net host \
    -v /opt/data/rocketmq-01/nameserver/logs:/home/rocketmq/logs \
    -e "JAVA_OPT_EXT=-Xms512M -Xmx512M -Xmn128m" \
    -e TZ=AsiaShanghai \
    --restart=always \
    apacherocketmq/rocketmq:4.9.2 \
    sh mqnamesrv
    
  • 节点2

    docker run -itd --name rocketmq-nameserver-02 --net host \
    -v /opt/data/rocketmq-02/nameserver/logs:/home/rocketmq/logs \
    -e "JAVA_OPT_EXT=-Xms512M -Xmx512M -Xmn128m" \
    -e TZ=AsiaShanghai \
    --restart=always \
    apacherocketmq/rocketmq:4.9.2 \
    sh mqnamesrv
    
  • 节点3

    docker run -itd --name rocketmq-nameserver-03 --net host \
    -v /opt/data/rocketmq-03/nameserver/logs:/home/rocketmq/logs \
    -e "JAVA_OPT_EXT=-Xms512M -Xmx512M -Xmn128m" \
    -e TZ=AsiaShanghai \
    --restart=always \
    apacherocketmq/rocketmq:4.9.2 \
    sh mqnamesrv
    

启动Broker

  • 节点1

    docker run -itd --name rocketmq-broker-01 --net host \
    -e "JAVA_OPT_EXT=-Xmx4096m -Xms4096m -Xmn2048m" \
    -e TZ=AsiaShanghai \
    -v /opt/data/rocketmq-01/broker/logs:/home/rocketmq/logs \
    -v /opt/data/rocketmq-01/broker/store:/home/rocketmq/store \
    -v /opt/data/rocketmq-01/broker/conf:/home/rocketmq/conf \
    --restart=always \
    apacherocketmq/rocketmq:4.9.2 \
    sh mqbroker -c /home/rocketmq/conf/broker.conf
    
  • 节点2

    docker run -itd --name rocketmq-broker-02 --net host \
    -e "JAVA_OPT_EXT=-Xmx4096m -Xms4096m -Xmn2048m" \
    -e TZ=AsiaShanghai \
    -v /opt/data/rocketmq-02/broker/logs:/home/rocketmq/logs \
    -v /opt/data/rocketmq-02/broker/store:/home/rocketmq/store \
    -v /opt/data/rocketmq-02/broker/conf:/home/rocketmq/conf \
    --restart=always \
    apacherocketmq/rocketmq:4.9.2 \
    sh mqbroker -c /home/rocketmq/conf/broker.conf
    
  • 节点3

    docker run -itd --name rocketmq-broker-03 --net host \
    -e "JAVA_OPT_EXT=-Xmx4096m -Xms4096m -Xmn2048m" \
    -e TZ=AsiaShanghai \
    -v /opt/data/rocketmq-03/broker/logs:/home/rocketmq/logs \
    -v /opt/data/rocketmq-03/broker/store:/home/rocketmq/store \
    -v /opt/data/rocketmq-03/broker/conf:/home/rocketmq/conf \
    --restart=always \
    apacherocketmq/rocketmq:4.9.2 \
    sh mqbroker -c /home/rocketmq/conf/broker.conf
    

RocketMQ控制台

docker run --restart=always -e TZ=Asia/Shanghai -itd -p 8789:8080 -e "NAMESRV_ADDR=172.16.0.4:9876;172.16.0.17:9876;172.16.0.14:9876" --name rocketmq-console apache/rocketmq-dashboard:1.0.0-centos

JAVA_OPTS=-Drocketmq.namesrv.addr=后接上自己NameServer的地址,多个用;隔开

启动成功后,通过IP加端口即可访问控制台.进入Cluster菜单查看集群,这里可以看到DLedger集群已成功搭建,并选举出了一个Master,其余两个都是Slave节点.

image-20210913141111525

测试发送消息

进入Topic菜单,选择一个Topic,我这里是新建的TEST,点SEND MASSAGE

image-20210913141312832

输入消息后点击COMMIT发送消息

image-20210913141433582

sendStatus显示SEND_OK

image-20210913141457372

回到Cluster菜单,看到三个节点均已正常复制数据.

image-20210913141532637

验证DLedger自动选举Master

将Master节点进程kill之后,验证是否会自动选举新的Master节点

image-20210913141704828

将Borker进程结束掉

image-20210913141754572

等待10s后,回到控制台,发现已经重新选举了一个新的Master节点

image-20210913141830429

重新启动节点后,会自动作为Slave节点加入集群

image-20210913141932001