STEP BY STEP带你使用Docker搭建MySql-MGR高可用集群

数据的重要性

数据已成为当今数字时代最重要的资产之一,对于企业的成功至关重要。它可以帮助企业了解客户、市场和自身运营,提高运营效率,做出明智决策,推动创新,并获得竞争优势。

数据的采集,存储,分析离不开企业的各种软件系统,这些数据最终都会存储在数据库中。确保数据安全,数据完整性,不丢失数据可以说是整个IT团队的责任,是保障系统正常运行和业务连续性的重要保证。

MySQL高可用方案

通常来讲,单台数据库服务器很容易就会发生单点故障,就很有可能造成业务数据的丢失,为了避免单点故障,生产环境的数据库都会采用高可用集群的方式进行部署。

MySQL有几中常见的高可用方案

  • MySQL复制(MySQL Replication)
  • MHA(Master High Availability)
  • MGR(MySQL Group Replication)

今天我们要讲的就是Mysql官方提供的MGR解决方案。更详细的内容,大家可以翻阅Mysql官方关于组复制的参考文档

MGR简单说明
MySQL Group Replication是MySQL数据库的一种高可用性解决方案,它是基于组复制(Group Replication)技术实现的。它允许多个MySQL服务器之间形成一个同步复制组,实现数据的自动复制和故障转移,从而提高了系统的可用性和容错性。

通过Docker容器模拟搭建一个MGR集群

我们进入今天的主题,带大家一步一步通过Docker容器来快速搭建一个MGR的集群。不过要声明一点,我们这个MGR集群是在本地电脑上模拟出的三个节点,实际上还是属于单点,只是为了让大家熟悉了理解MGR集群创建的整个过程,生产环境请不要按这种方式操作。

容器环境的准备

如果我们的操作系统上还没有安装Docker运行时环境的,可以参考我写的另两篇文章

准备工作

  • 创建容器网络
  • 创建工作目录

创建容器网络

#创建容器网络,并指定subnet
docker network create --subnet=172.20.0.0/16 mysql-mgr

#检查容器网络
vian@txzq1899-ubuntu:~$ docker network inspect mysql-mgr 
[
    {
        "Name": "mysql-mgr",
        "Id": "6d33e30330ed998c7ceb26971455479d5642d04e015bcfbab720733f9655bd80",
        "Created": "2024-05-07T17:38:32.975808257+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.20.0.0/16"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        }
]

创建工作目录
工作目录主要是用于存放脚本,初始配置文件,容器数据卷,用户名&密码文件

vian@txzq1899-ubuntu:~/ws/mysql$ ll
总计 24
drwxrwxr-x  6 vian vian 4096  58 01:34 ./
drwxrwxr-x 10 vian vian 4096  58 09:40 ../
drwxrwxr-x  5 vian vian 4096  58 01:42 conf/
drwxrwxr-x  5  999 vian 4096  58 01:27 data/
drwxrwxr-x  2 vian vian 4096  58 01:45 script/
drwxrwxr-x  2 vian vian 4096  58 09:50 secrets/

vian@txzq1899-ubuntu:~/ws/mysql/secrets$ ll
总计 16
drwxrwxr-x 2 vian vian 4096  58 09:50 ./
drwxrwxr-x 6 vian vian 4096  58 01:34 ../
-rw-rw-r-- 1 vian vian   11  57 10:38 mysql-root
-rw-rw-r-- 1 vian vian   11  57 10:38 repl-user


脚本源码
本文中所有的操作步骤我都已经进行了脚本化,大家可以上我的github repo上自行下载相关的脚本。

地址如下:MySQL Containerize

https://github.com/TXZQ1899/containerize.git

STEP1、初始化Mysql实例

  • 创建三个MySQL容器
  • 映射数据卷
  • 分配IP地址

以下是脚本源码

  • 容器IP与准备工作中的子网是对应上的。
  • 映射了数据卷
    • 数据库文件
    • 密码文件

我们看到,第一次创建和启动容器是没有使用自定义的my.cnf配置文件的,采用默认方式启动3个MySQL容器节点。

#!/bin/bash

# MySQL的docker容器名
container_names=("mysql-1" "mysql-2" "mysql-3")

# MySQL宿主机端口
host_ports=(3306 3307 3308)
host_ports_x=(13306 13307 13308)
container_ips=("172.20.0.11" "172.20.0.12" "172.20.0.13")

# 批量创建MySQL容器
for i in ${!container_names[@]}
do
    docker run --name ${container_names[$i]} \
    --net mysql-mgr --ip ${container_ips[$i]} \
    -d -p ${host_ports[$i]}:3306 -p ${host_ports_x[$i]}:33061 \
    -v ~/ws/mysql/data/${container_names[$i]}:/var/lib/mysql \
    -v ~/ws/mysql/secrets:/run/secrets \
    -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql-root \
    mysql:latest
    
    echo "Mysql container : ${container_names[$i]} has been created!"
done

echo "Step 1: MySQL Cluster Initialization Completed!"

STEP2、创建MGR配置文件

这里只是准备三个节点的配置文件,用于第四步中更新配置文件。同样也是使用脚本来批量创建。

vian@txzq1899-ubuntu:~/ws/mysql/conf$ tree
.
├── mysql-1
│   └── my.cnf
├── mysql-2
│   └── my.cnf
└── mysql-3
    └── my.cnf

3 directories, 3 files

请注意源码中,这个组名是一个UUID,大家自行生成即可。

group_replication_group_name="bc946766-0c46-11ef-a8e2-0242ac110002" 

脚本源码如下:

#!/bin/bash

# mysql安装路径
mysql_base_path=~/ws/mysql/conf/

rm -rf ~/ws/mysql/conf/*

# 节点数量和起始IP地址
node_count=3
base_ip="172.20.0.11"

# 将起始IP地址分割成数组
IFS='.' read -ra ADDR <<< "$base_ip"

# 计算最后一个IP片段的起始数字
last_octet=${ADDR[3]}

# 创建配置文件
for ((i=1; i<=node_count; i++))
do
    # 计算每个节点的IP地址
    ip="172.20.0.$((last_octet + i - 1))"
    
    # MySQL配置路径
    conf_path=${mysql_base_path}/mysql-${i}

    # 创建目录
    mkdir -p ${conf_path}

    # 将节点配置写入对应的my.cnf文件
    cat > ${conf_path}/my.cnf <<EOF
[mysqld]
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"

server_id=${i}
gtid_mode=ON
enforce_gtid_consistency=ON

plugin_load_add='group_replication.so'

group_replication_group_name="bc946766-0c46-11ef-a8e2-0242ac110002" 
group_replication_start_on_boot=off
group_replication_local_address= "${ip}:33061"
group_replication_group_seeds= "172.20.0.$((last_octet)):33061,172.20.0.$((last_octet + 1)):33061,172.20.0.$((last_octet + 2)):33061"
group_replication_bootstrap_group=off
EOF


done
tree ~/ws/mysql/conf 
echo "MGR配置文件创建完毕!"

STEP3、安装Group Replication插件

这一步是要在三个MySQL实例上安装group replication插件,需要在每一个MySQL实例的命令行执行安装指令。

mysql > install PLUGIN group_replication SONAME 'group_replication.so';

因为我们的MySQL实例部署在docker 容器中,所以需要通过docker exec 这个命令在容器内执行相应的SQL语句。

#mysql-1 是容器名称
#mysql,是容器中的mysql客户端, 
#-u,-p mysql用户名,密码
#-e "sql command;",要执行的SQL
docker exec -it mysql-1 \
mysql -uroot -phelloworld -e "sql command;"

第三步的脚本源码如下:

#!/bin/bash

# 用户信息设置
CONTAINER_NAMES=("mysql-1" "mysql-2" "mysql-3")

# 从环境变量读取root密码
MYSQL_ROOT_PASSWORD=$(<~/ws/mysql/secrets/mysql-root)

# 在每个MySQL实例上执行创建用户和设置权限的步骤
for CONTAINER in "${CONTAINER_NAMES[@]}"
do
    docker exec -it $CONTAINER mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "
    install PLUGIN group_replication SONAME 'group_replication.so';
    "
done

echo "Done"

STEP4、更新MySQL配置文件

这一步比较简单,就是需要将第二步创建的配置文件,复制到容器中mysql配置文件存储的地方。

主要通过docker cp命令实现

docker cp /path/to/file/filename container_name:/path/in/container

批量更新脚本源码如下 :

#!/bin/bash

# MySQL的docker容器名
container_names=("mysql-1" "mysql-2" "mysql-3")


# 批量更新MGR配置文件
for i in ${!container_names[@]}
do
    docker cp ~/ws/mysql/conf/${container_names[$i]}/my.cnf ${container_names[$i]}:/etc/mysql/conf.d 
done

echo "Configuration update complete!"

STEP5、重启MySQL实例

更新完配置文件后需要批量重启MySQL实例,这个也比较简单,通过docker restart container_name来实现
脚本源码如下:

#!/bin/bash

# MySQL的docker容器名
container_names=("mysql-1" "mysql-2" "mysql-3")

# 批量重启MySQL容器
for i in ${!container_names[@]}
do
    docker restart ${container_names[$i]} 
done

echo "Container restart is complete!"

STEP6、创建Replication用户

这一步需要创建用于Replication的用户,授权等操作。和第三步类似,也是通过docker exec在容器内执行相应SQL语句。

具体的SQL语句参考官方文档:

脚本源码如下 :

#!/bin/bash

# 用户信息设置
USER='rpl_user'
PASSWORD=$(<~/ws/mysql/secrets/repl-user)
CONTAINER_NAMES=("mysql-1" "mysql-2" "mysql-3")

# 从环境变量读取root密码
MYSQL_ROOT_PASSWORD=$(<~/ws/mysql/secrets/mysql-root)

# 在每个MySQL实例上执行创建用户和设置权限的步骤
for CONTAINER in "${CONTAINER_NAMES[@]}"
do
    docker exec -it $CONTAINER mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "
    SET SQL_LOG_BIN=0;

    CREATE USER IF NOT EXISTS '$USER'@'%' IDENTIFIED BY '$PASSWORD';
    GRANT REPLICATION SLAVE, CONNECTION_ADMIN, BACKUP_ADMIN ON *.* TO '$USER'@'%';
    GRANT GROUP_REPLICATION_STREAM ON *.* TO '$USER'@'%';
    FLUSH PRIVILEGES;

    SET SQL_LOG_BIN=1;
        
    CHANGE REPLICATION SOURCE TO SOURCE_USER='$USER',
        SOURCE_PASSWORD='$PASSWORD' FOR CHANNEL 'group_replication_recovery';
    "
done

echo "Done"

STEP7、设置和开启组复制

这一步就是设置和开启组复制功能,也是需要在数据库中执行相应的SQL指令。

开启组复制的SQL指令参考官方文档:

MySQL官方称之为引导,指引中有明确讲到:引导应该只由单个服务器完成,即启动群组的服务器,并且只能执行一次。

The process of starting a group for the first time is called bootstrapping. You use the group_replication_bootstrap_group system variable to bootstrap a group. The bootstrap should only be done by a single server, the one that starts the group and only once.

所以最终的脚本如下:

#!/bin/bash

# 用户信息
USER='rpl_user'
PASSWORD=$(<~/ws/mysql/secrets/repl-user)
MYSQL_ROOT_PASSWORD=$(<~/ws/mysql/secrets/mysql-root)

container_names=("mysql-1" "mysql-2" "mysql-3") # 所有容器的名称

for CONTAINER in "${container_names[@]}"
do
  if [ "$CONTAINER" == "mysql-1" ]; then
    # 如果是master容器,执行bootstrapping命令
    echo "Initializing the master ($CONTAINER)..."
    docker exec -it $CONTAINER mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "
      SET GLOBAL group_replication_bootstrap_group=ON;
      START GROUP_REPLICATION USER='$USER', PASSWORD='$PASSWORD';
      SET GLOBAL group_replication_bootstrap_group=OFF;
    "
  else
    # 如果是其它容器,则加入已有集群
    echo "Adding the slave ($CONTAINER) to the group..."
    docker exec -it $CONTAINER mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "
      START GROUP_REPLICATION USER='$USER', PASSWORD='$PASSWORD';
    "
  fi
done

echo "Group replication started for all nodes."

STEP8、检查MGR集群状态

这一步就是检查一下MGR集群的状态,也是通过执行MySQL指令的形式

脚本源码如下:

#!/bin/bash
MYSQL_ROOT_PASSWORD=$(<~/ws/mysql/secrets/mysql-root)
docker exec -it mysql-1 mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "
      SELECT * FROM performance_schema.replication_group_members;
    "

MySQL-MGR-Cluster搭建完成

大家可以在主库上进行一些数据库操作,看看从库是否能实现数据同步。
也可以通过docker stop关闭mysql-1节点(Master),看看MGR机制是否能完成主从的切换。

vian@txzq1899-ubuntu:~/ws/mysql/script$ docker ps
CONTAINER ID   IMAGE          COMMAND                   CREATED        STATUS        PORTS                                                                                                 NAMES
84531a0b4f0d   mysql:latest   "docker-entrypoint.s…"   12 hours ago   Up 12 hours   33060/tcp, 0.0.0.0:3308->3306/tcp, :::3308->3306/tcp, 0.0.0.0:13308->33061/tcp, :::13308->33061/tcp   mysql-3
f91d0848fac2   mysql:latest   "docker-entrypoint.s…"   12 hours ago   Up 12 hours   33060/tcp, 0.0.0.0:3307->3306/tcp, :::3307->3306/tcp, 0.0.0.0:13307->33061/tcp, :::13307->33061/tcp   mysql-2
e7f3589bdeac   mysql:latest   "docker-entrypoint.s…"   12 hours ago   Up 12 hours   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp, 0.0.0.0:13306->33061/tcp, :::13306->33061/tcp   mysql-1
vian@txzq1899-ubuntu:~/ws/mysql/script$ 

vian@txzq1899-ubuntu:~/ws/mysql/script$ ./8.check-mgr-cluster-member-status.sh 
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------------------+--------------------------------------+--------------+-------------+--------------+-------------+----------------+----------------------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST  | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | MEMBER_COMMUNICATION_STACK |
+---------------------------+--------------------------------------+--------------+-------------+--------------+-------------+----------------+----------------------------+
| group_replication_applier | 122dd904-0c97-11ef-a155-0242ac14000b | e7f3589bdeac |        3306 | ONLINE       | PRIMARY     | 8.4.0          | XCom                       |
| group_replication_applier | 125ddf4e-0c97-11ef-a1fb-0242ac14000c | f91d0848fac2 |        3306 | ONLINE       | SECONDARY   | 8.4.0          | XCom                       |
| group_replication_applier | 12a8bbac-0c97-11ef-a14f-0242ac14000d | 84531a0b4f0d |        3306 | ONLINE       | SECONDARY   | 8.4.0          | XCom                       |
+---------------------------+--------------------------------------+--------------+-------------+--------------+-------------+----------------+----------------------------+

#所有的脚本如下,只需要按次序依次执行即可。
vian@txzq1899-ubuntu:~/ws/mysql/script$ ll
总计 56
drwxrwxr-x 2 vian vian 4096  58 01:45 ./
drwxrwxr-x 6 vian vian 4096  58 01:34 ../
-rwxr-xr-x 1 vian vian  766  58 01:26 1.init-cluster.sh*
-rwxr-xr-x 1 vian vian 1210  58 01:45 2.init-conf.sh*
-rwxrwxr-x 1 vian vian  450  57 22:52 3.install-gr-plugin.sh*
-rwxr-xr-x 1 vian vian  300  58 01:11 4.update-mgr-conf.sh*
-rwxr-xr-x 1 vian vian  260  58 01:13 5.restart-cluster.sh*
-rwxrwxr-x 1 vian vian  861  57 22:52 6.create-repl-user.sh*
-rwxr-xr-x 1 vian vian  989  58 00:58 7.setup-group-replication.sh*
-rwxr-xr-x 1 vian vian  207  58 01:41 8.check-mgr-cluster-member-status.sh*
-rwxr-xr-x 1 vian vian  118  57 17:25 cleanup.sh*
-rwxr-xr-x 1 vian vian   88  57 17:07 remove-cluster.sh*
-rwxr-xr-x 1 vian vian  228  58 01:37 start-cluster.sh*
-rwxr-xr-x 1 vian vian  228  58 01:38 stop-cluster.sh*

留一个思考题,MGR只是保证了MySQL集群的高可用,MGR能自动进行主从的切换,但我们的应用是感知不到这个动作的发生的。一般来讲应用通过域名连接到这个MySQL-MGR-集群,域名又是指向的哪里?如何保证应用能准确的连接到新的主库上呢?

关注我的公众号

欢迎大家关注、点赞、转发,一起交流软件开发、架构设计、云原生技术。
TXZQ聊IT技术与架构

  • 24
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值