• MySQL高可用-使用Docker部署MGR

MySQL高可用-使用Docker部署MGR

2025-08-16 12:33:59 栏目:宝塔面板 0 阅读

MySQL 的高可用方案很多,有 MHA、MGR、MySQL InnoDB Cluster 等。起初想学习下 MHA,了解后发现 MHA 在 Github 上的仓库已经没有更新了。不过 MHA 的兼容性比较好,有老版本的 MySQL 需要做高可用,还是值得一试的。

本文介绍下 MGR 的部署。

MGR (MySQL Group Replication) 是 MySQL 5.7.17 提出的,既可以很好的保证数据一致性又可以自动切换,具备故障检测功能、支持多节点写入。是以插件的形式提供,可以灵活部署。

MySQL MGR 集群是多个 MysQL Server 节点共同组成的分布式集群,每个 Server 都有完整的副本,它是基于 ROW 格式的二进制日志文件和 GTID 特性来实现的。

MGR 的优点

  • 强一致性:基于原生复制及 Paxos 协议的组复制技术(以插件形式提供),确保数据的严格一致性。
  • 高容错性:在少数节点故障时仍可正常运行,具备自动故障检测机制。节点间资源冲突采用无锁设计(如先到者优先)处理,避免错误。
  • 高扩展性:支持节点动态自动加入与移除。新节点加入后自动同步数据至一致状态;节点移除后,集群自动更新并维护组配置信息。
  • 高灵活性:支持单主模式与多主模式。单主模式下自动选举主节点,所有写操作路由至主节点;多主模式下,所有节点均可并发处理写操作。

MGR 的一些限制

  • 仅支持 InnoDB 表,并且每个表一定要有一个主键。
  • 必须打开 GTID 特性,二进制日志格式必须设置为 ROW 。
  • MGR 不支持大事务。
  • 仅支持 IPv4 网络,组大小限制为最少3个节点、最多9个节点。
  • 不支持外键。
  • 二进制日志不支持 Binlog Event Checksum 。
  • 所有节点 server_id 和 server_uuid 需唯一。

部署前准备

  • 为了方便,mysql 的主节点和从节点在一台虚拟机中进行测试
  • docker 版本:20.10.0
  • docker compose 版本:2.26.2
  • mysql 版本:8.0.39

开始部署

采用 docker-compose 的方式进行部署,部署目录 mysql-mgr 的文件结构如下图:

  • docker-compose.yml:容器编排文件,配置一个主和两个从的 mysql 节点。
  • mysql-config:此目录中是主和从的 mysql 配置文件
  • mysql-init-srcipts:此目录中是 mysql 启动时需要创建复制账号以及安装 mgr 插件
  • start-mgr.sh:三个 mysql 节点启动后,执行该文件进行 mgr 集群的启动。

将 mysql-mgr 拷贝到服务器,进入 mysql-mgr 目录执行 docker-compose up -d 。

等三个 mysql 节点的状态正常,执行 ./start-mgr.sh ,成功执行如下图所示。

进入任意一个 mysql 中,执行 SELECT * FROM performance_schema.replication_group_members; ,三个节点的 MEMBER_STATE 为 ONLINE 说明部署成功。

现在可以连上主节点,进行库表和数据的创建,来验证是否正常同步到从节点。

关键点说明

docker-compose 配置

docker-compose.yml 文件定义了三个 MySQL 节点,分别是一个主节点和两个从节点:

version: '3.8'

services:
  mysql-master:
    image: mysql:8.0.39
    container_name: mysql-master
    hostname: mysql-master
    command: ["mysqld"]
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_DATABASE: mydb
    volumes:
      - mysql-master-data:/var/lib/mysql
      - ./mysql-init-scripts:/docker-entrypoint-initdb.d
      - ./mysql-config/mysql-master.cnf:/etc/mysql/conf.d/mysql-master.cnf
    ports:
      - "3306:3306"
      - "33061:33061"
    networks:
      - mysql-mgr-network
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD"]
      interval: 10s
      timeout: 5s
      retries: 5

  mysql-slave-1:
    image: mysql:8.0.39
    container_name: mysql-slave-1
    hostname: mysql-slave-1
    command: ["mysqld"]
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_DATABASE: mydb
    volumes:
      - mysql-slave-1-data:/var/lib/mysql
      - ./mysql-init-scripts:/docker-entrypoint-initdb.d
      - ./mysql-config/mysql-slave-1.cnf:/etc/mysql/conf.d/mysql-slave-1.cnf
    ports:
      - "3307:3306"
      - "33062:33061"
    networks:
      - mysql-mgr-network
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD"]
      interval: 10s
      timeout: 5s
      retries: 5
    depends_on:
      - mysql-master

  mysql-slave-2:
    image: mysql:8.0.39
    container_name: mysql-slave-2
    hostname: mysql-slave-2
    command: ["mysqld"]
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_DATABASE: mydb
    volumes:
      - mysql-slave-2-data:/var/lib/mysql
      - ./mysql-init-scripts:/docker-entrypoint-initdb.d
      - ./mysql-config/mysql-slave-2.cnf:/etc/mysql/conf.d/mysql-slave-2.cnf
    ports:
      - "3308:3306"
      - "33063:33061"
    networks:
      - mysql-mgr-network
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD"]
      interval: 10s
      timeout: 5s
      retries: 5
    depends_on:
      - mysql-master

networks:
  mysql-mgr-network:
    driver: bridge

volumes:
  mysql-master-data:
  mysql-slave-1-data:
  mysql-slave-2-data:

卷挂载,以主节点为例:

  • 数据持久化:mysql-master-data:/var/lib/mysql
  • 初始化脚本:./mysql-init-scripts:/docker-entrypoint-initdb.d
  • 配置文件:./mysql-config/mysql-master.cnf:/etc/mysql/conf.d/mysql-master.cnf

端口映射:

  • MySQL 节点端口:3306:3306(主节点),3307:3306(从节点1),3308:3306(从节点2)
  • MGR 通信端口:33061:33061(主节点),33062:33061(从节点1),33063:33061(从节点2)

网络配置

  • 所有节点都连接到同一个网络 mysql-mgr-network,确保节点间可以相互通信

MySQL 的配置文件

[mysqld]
server-id=1
log-bin=mysql-bin-1.log
binlog-format=ROW
gtid-mode=ON
enforce-gtid-cnotallow=ON
log-slave-updates=ON
binlog-checksum=NONE
master-info-repository=TABLE
relay-log-info-repository=TABLE
transaction-write-set-extractinotallow=XXHASH64
  • server-id:每个节点的必须唯一。
  • binglog-format:行级 binlog,MGR 硬性要求 ROW 格式。
  • gtid-mode:启用 GTID(全局事务标识),MGR 内部完全基于 GTID 做事务认证和冲突检测。
  • enforce-gtid-consistency:禁止任何会破坏 GTID 一致性的语句(如 CREATE TEMPORARY TABLE 与 CREATE TABLE ... SELECT),MGR 强制要求打开,否则无法启动组复制。
  • binlog-checksum:MySQL 8.0.20 之前的 MGR 要求关闭 binlog 校验和(因为早期组通信层不支持),8.0.20 及以后可以改为 CRC32,保持默认即可,但旧版本必须显式设置为 NONE

这些参数共同确保节点开启 binlog、使用 ROW + GTID、写入复制元数据到 InnoDB 表,并为 MGR 提供事务写集合,从而满足组复制的所有前置条件。

除此之外,还需要进行 MGR 的组复制配置,如下:

loose-group-replication-group-name=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
loose-group-replication-start-on-boot=OFF
loose-group-replication-local-address=mysql-master:33061
loose-group-replication-group-seeds=mysql-master:33061,mysql-slave-1:33061,mysql-slave-2:33061
loose-group-replication-bootstrap-group=OFF
loose-group-replication-single-primary-mode=ON
loose-group-replication-enforce-update-everywhere-checks=OFF
  • 给整个 MGR 组起一个全局唯一的名字(UUID 格式),三个节点相同。
  • MySQL 实例启动时不自动启动 Group Replication 插件,这个参数如果设置为 OFF,当坏掉的节点修复后,不会自动加入集群。
  • 本节点在组内通信时使用的本地监听地址(IP 或主机名:端口)。
  • 种子列表,告诉当前节点“初次加入组时可以去找谁”。只要列表中的任意一个节点在线,新节点就能拿到完整的成员信息并加入组。通常把所有成员都写上,方便任何顺序启动。
  • 只在第一个节点第一次启动时设为 ON,用来创建组;之后必须立即改回 OFF 并重启,否则会出现“脑裂”或成员冲突。
  • 打开单主模式(Single-Primary),组内只有一台节点可写(primary),其余为只读(secondaries),主节点故障时自动重新选举。
  • 在多主模式下才生效;单主模式可保持 OFF。

初始化脚本

-- 01-create-replication-user.sql
-- 创建复制用户
CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'replpass';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
GRANT BACKUP_ADMIN ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;

reset master;

上面的脚本有两个点需要注意:

  • WITH mysql_native_password 必须要加上
  • 最后的 reset master 不要忘记了
-- 02-install-plugin.sql
INSTALL PLUGIN group_replication SONAME 'group_replication.so';

这些脚本在容器首次启动时自动执行:

  • 创建具有复制权限的用户 repl
  • 安装 Group Replication 插件

启动 MGR 集群

启动 MGR 集群的过程由 start-mgr.sh 脚本完成:

#!/bin/bash

# 等待所有MySQL实例启动完成
sleep 30

# 在主节点上引导组并启动组复制
docker exec mysql-master mysql -uroot -prootpassword -e "
  CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replpass' FOR CHANNEL 'group_replication_recovery';
  SET GLOBAL group_replication_bootstrap_group=ON;
  START GROUP_REPLICATION;
  SET GLOBAL group_replication_bootstrap_group=OFF;
  SELECT * FROM performance_schema.replication_group_members;"

# 等待主节点组复制启动完成
sleep 20

# 在从节点上启动组复制
docker exec mysql-slave-1 mysql -uroot -prootpassword -e "
  CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replpass' FOR CHANNEL 'group_replication_recovery';
  START GROUP_REPLICATION;
  SELECT * FROM performance_schema.replication_group_members;"

docker exec mysql-slave-2 mysql -uroot -prootpassword -e "
  CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replpass' FOR CHANNEL 'group_replication_recovery';
  START GROUP_REPLICATION;
  SELECT * FROM performance_schema.replication_group_members;"

# 检查MGR状态
sleep 5
echo "检查MGR集群状态:"
docker exec mysql-master mysql -uroot -prootpassword -e "SELECT * FROM performance_schema.replication_group_members;"

主节点:

  • 配置复制恢复通道的用户名和密码。
  • 设置 group_replication_bootstrap_group=ON 引导组。
  • 启动组复制 START GROUP_REPLICATION。
  • 关闭引导模式 group_replication_bootstrap_group=OFF。
  • 只有第一个节点需要引导组,其他节点只需加入。

从节点:

  • 配置相同的复制恢复通道。
  • 直接启动组复制,自动加入已存在的组。

常见问题

遇到问题很正常,出现任何错误优先查看 mysql 节点的日志,根据错误信息让 AI 分析并给出解决方案,通常都是可以解决的。

我部署过程中就遇到执行 ./start-mgr.sh 后,查询状态如下图:

只有主节点是 ONLINE。我对主从节尝试手动停止和启用组复制后解决。

STOP GROUP_REPLICATION; 
START GROUP_REPLICATION;

在学习过程中出现问题其实是好事,可以从解决问题的过程中去提高。之前碰到有同事遇到问题就重置服务器,其实是在走捷径,能力得不到提升,而且不是所有的环境都能重置的。搞懂所有细枝末节才能以不变应万变。

希望本文对您有所帮助!

本文地址:https://www.yitenyun.com/348.html

搜索文章

Tags

数据库 API FastAPI Calcite 电商系统 MySQL Web 应用 异步数据库 数据同步 ACK 双主架构 循环复制 Deepseek 宝塔面板 Linux宝塔 Docker 生命周期 JumpServer JumpServer安装 堡垒机安装 Linux安装JumpServer 序列 核心机制 esxi esxi6 root密码不对 无法登录 web无法登录 SSL 堡垒机 跳板机 HTTPS Windows Windows server net3.5 .NET 安装出错 宝塔面板打不开 宝塔面板无法访问 查看硬件 Linux查看硬件 Linux查看CPU Linux查看内存 连接控制 机制 HTTPS加密 Windows宝塔 Mysql重置密码 无法访问宝塔面板 HexHub 运维 Oracle 处理机制 Serverless 无服务器 语言 Spring Redis 异步化 ES 协同 技术 group by 索引 InnoDB 数据库锁 监控 开源 PostgreSQL 存储引擎 分页查询 高可用 SQL 动态查询 响应模型 缓存方案 缓存架构 缓存穿透 R edis 线程 数据 主库 自定义序列化 服务器 管理口 scp Linux的scp怎么用 scp上传 scp下载 scp命令 日志文件 MIXED 3 查询 SVM Embedding 存储 OB 单机版 Linux 安全 工具 电商 系统 SQLark SQLite-Web SQLite 数据库管理工具 架构 Rsync Postgres OTel Iceberg RocketMQ 长轮询 配置 Recursive 云原生 流量 共享锁 防火墙 黑客 • 索引 • 数据库 修改DNS Centos7如何修改DNS 向量数据库 大模型 聚簇 非聚簇 sftp 服务器 参数 PG DBA 缓存 业务 AI 助手 Ftp ​Redis 机器学习 推荐模型 场景 GreatSQL 连接数 优化 万能公式 Netstat Linux 服务器 端口 数据备份 MySQL 9.3 openHalo 数据分类 加密 同城 双活 信息化 智能运维 RDB AOF INSERT COMPACT 窗口 函数 人工智能 推荐系统 核心架构 订阅机制 事务 Java 开发 MVCC 磁盘架构 线上 库存 预扣 redo log 重做日志 网络架构 网络配置 Doris SeaTunnel prometheus Alert Redisson 锁芯 向量库 Milvus mini-redis INCR指令 Undo Log 高效统计 今天这篇文章就跟大家 Python 引擎 性能 网络故障 B+Tree ID 字段 模型 IT运维 Canal Web PostGIS Redis 8.0 不宕机 数据脱敏 加密算法 R2DBC Hash 字段 分布式 集中式 崖山 新版本 自动重启 Pottery ZODB 微软 SQL Server AI功能 容器化 虚拟服务器 虚拟机 内存 OAuth2 Token JOIN Entity DBMS 管理系统 MongoDB 容器 数据类型 数据结构 读写 sqlmock 启动故障 悲观锁 乐观锁 分库 分表 LRU SpringAI StarRocks 数据仓库 数据集成工具 分页 单点故障 QPS 高并发 传统数据库 向量化 数据页 工具链 Testcloud 云端自动化 Redka 排行榜 排序 发件箱模式 事务隔离 部署 聚簇索引 非聚簇索引 分页方案 排版 filelock 大表 业务场景 意向锁 记录锁 速度 服务器中毒 Web 接口 1 SSH 池化技术 连接池 Caffeine CP 仪表盘 分布式架构 分布式锁​ dbt 数据转换工具 日志 原子性 EasyExcel MySQL8 AIOPS MCP 开放协议 优化器 网络 InfluxDB Order IT 双引擎 RAG HelixDB 频繁 Codis Go 数据库迁移 字典 单线程 Ansible 对象 Crash 代码 LLM 事务同步 订单 线程安全 Pump List 类型 UUIDv7 主键 服务器性能 锁机制 MGR 分布式集群 并发控制 恢复机制 Next-Key 国产 用户 RR 互联网 语句 拦截器 动态代理 TIME_WAIT 负载均衡 播客 行业 趋势 分布式锁 Zookeeper 解锁 调优 ReadView 国产数据库 闪回 产业链 兼容性 快照读 当前读 视图 关系数据库 编程 数据字典 算法 主从复制 代理 GitHub Git count(*) count(主键) 行数 UUID ID 神经系统 慢SQL优化 千万级 表空间 Valkey Valkey8.0 矢量存储 数据库类型 AI代理 查询规划 恢复数据 CAS 失效 多线程 技巧 Weaviate