mysql docker 主从复制场景

场景 1、mysql 主从复制需要要精确到库表

2、从库对应多主

3、主主复制

 

创建目录

sudo mkdir -p /app/mysql/data

sudo mkdir -p /app/mysql/conf

创建compose

cat docker-compose.yml 
services:
  mysql:
    image: mysql:8.0.36
    container_name: mysql-master2
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: 数据密码
    ports:
      - "3306:3306"
    volumes:
      - ./data:/var/lib/mysql
      - ./conf/:/etc/mysql/conf.d/

配置master 配置文件

cat conf/my.cnf

[mysqld]
bind-address=0.0.0.0
###############################################
port=3306
skip_name_resolve=ON
max_connections=500

# 线程优化
thread_cache_size=100
default_storage_engine=InnoDB
innodb_buffer_pool_size=10G
innodb_buffer_pool_instances=8
innodb_log_file_size=2G
innodb_log_files_in_group=2
innodb_flush_log_at_trx_commit=1
innodb_flush_method=O_DIRECT

# =========================
# IO优化
# =========================
innodb_io_capacity=200
innodb_io_capacity_max=500
innodb_read_io_threads=4
innodb_write_io_threads=4
# =========================
# 临时表
# =========================
tmp_table_size=128M
max_heap_table_size=128M
# =========================
# 表缓存
# =========================
table_open_cache=4096
table_definition_cache=2048
# =========================
# binlog复制
# =========================
server-id=1
log-bin=mysql-bin
binlog_format=ROW
gtid_mode=ON
enforce_gtid_consistency=ON
log_slave_updates=ON
binlog_cache_size=64K
max_binlog_cache_size=1G
#保留7天
binlog_expire_logs_seconds=604800
# =========================
# 慢SQL
# =========================
#slow_query_log=ON
#long_query_time=2
#log_queries_not_using_indexes=OFF
# =========================
# 字符集
# =========================
character-set-server=utf8mb4
collation-server=utf8mb4_0900_ai_ci

########主库写#########
binlog_group_commit_sync_delay=0
binlog_group_commit_sync_no_delay_count=0
sync_binlog=1

#########双主模式才会用########
# 在上主库1 (my.cnf)
#auto_increment_increment = 2
#auto_increment_offset = 1

# 在上主库2 (my.cnf)
#auto_increment_increment = 2
#auto_increment_offset = 2

配置slave配置文件

cat conf/my.cnf 

[mysqld]
bind-address=0.0.0.0
###############################################
port=3306
skip_name_resolve=ON
max_connections=500

# 线程优化
thread_cache_size=100
default_storage_engine=InnoDB
innodb_buffer_pool_size=10G
innodb_buffer_pool_instances=8
innodb_log_file_size=2G
innodb_log_files_in_group=2
innodb_flush_log_at_trx_commit=1
innodb_flush_method=O_DIRECT

# =========================
# IO优化
# =========================
innodb_io_capacity=200
innodb_io_capacity_max=500
innodb_read_io_threads=4
innodb_write_io_threads=4
# =========================
# 临时表
# =========================
tmp_table_size=128M
max_heap_table_size=128M
# =========================
# 表缓存
# =========================
table_open_cache=4096
table_definition_cache=2048
# =========================
# binlog复制
# =========================
server-id=3
log-bin=mysql-bin
binlog_format=ROW
gtid_mode=ON
enforce_gtid_consistency=ON
log_slave_updates=ON
binlog_cache_size=64K
max_binlog_cache_size=1G
#保留7天
binlog_expire_logs_seconds=604800
# =========================
# 慢SQL
# =========================
#slow_query_log=ON
#long_query_time=2
#log_queries_not_using_indexes=OFF
# =========================
# 字符集
# =========================
character-set-server=utf8mb4
collation-server=utf8mb4_0900_ai_ci

##########从库复制模式##########
replica_parallel_type=LOGICAL_CLOCK
replica_parallel_workers=4
relay_log_recovery=ON

relay-log=relay-bin
replica_parallel_workers=4
replica_preserve_commit_order=ON
#指定复制表
#replicate-wild-do-table=shop.user
#replicate-wild-do-table=shop.orders
# 忽略日志表
#replicate-ignore-table=shop.logs

#####设置只读模式########
read_only=ON
super_read_only=ON

创建同步用户,只需在一个master上创建后续会自动同步

CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY '同步用户密码';

#授权用户
GRANT REPLICATION SLAVE ON *.*  TO 'repl'@'%';

FLUSH PRIVILEGES;

#确认
SELECT user,host,plugin FROM mysql.user WHERE user='repl';

#确认用户权限
SHOW GRANTS FOR 'repl'@'%';

创建master1 和master2 主主复制

mastert1 :

CHANGE REPLICATION SOURCE TO
SOURCE_HOST='10.10.0.69',
SOURCE_PORT=3306,
SOURCE_USER='repl',
SOURCE_PASSWORD='qkrepl@cloud',
SOURCE_AUTO_POSITION=1;

START REPLICA;

mastert2:

CHANGE REPLICATION SOURCE TO
SOURCE_HOST='10.10.0.68',
SOURCE_PORT=3306,
SOURCE_USER='repl',
SOURCE_PASSWORD='qkrepl@cloud',
SOURCE_AUTO_POSITION=1;

START REPLICA;


查看SHOW REPLICA STATUS\G
或者show slave status\G;

创建 一个 Slave 同时同步两个 Master

同步master1
CHANGE REPLICATION SOURCE TO
SOURCE_HOST='10.10.0.68',
SOURCE_PORT=3306,
SOURCE_USER='repl',
SOURCE_PASSWORD='qkrepl@cloud',
SOURCE_AUTO_POSITION=1
FOR CHANNEL 'master1';

START REPLICA FOR CHANNEL 'master1';


同步mastert2
CHANGE REPLICATION SOURCE TO
SOURCE_HOST='10.10.0.69',
SOURCE_PORT=3306,
SOURCE_USER='repl',
SOURCE_PASSWORD='qkrepl@cloud',
SOURCE_AUTO_POSITION=1
FOR CHANNEL 'master2';

START REPLICA FOR CHANNEL 'master2';

查看:
SHOW REPLICA STATUS FOR CHANNEL 'master1'\G
SHOW REPLICA STATUS FOR CHANNEL 'master2'\G

 

#注意事项 若slave 只配置了表同步 slave上一定要先创建库 因为slave 不会主动复制库

 

#xtrabackup 备份策略与恢复方式

备份脚本

恢复脚本

XtraBackup 物理备份(容器化)—— MySQL 8.0.36

一、方案对比

维度 物理备份(XtraBackup, 本目录脚本)
原理 拷贝 .ibd + 重做日志,文件级
备份速度 快(文件拷贝)
恢复速度 快(copy-back 后直接启库)
锁影响 更短(Backup Locks),对写负载更友好
备份粒度 仅整实例
体积 与数据目录相当
典型用途 大库日常备份、从库重建

二、与 8.0.36 的版本匹配

镜像 percona/percona-xtrabackup:8.0.35-30(默认)
兼容性 Percona 官方实测 8.0.35-30 可备份 MySQL 8.0.36;8.0.34 起 PXB 已移除服务器版本硬校验
升级建议 若 MySQL 升到 8.0.4x,用环境变量 XB_IMAGE 换到最新 8.0.35-x 构建;PXB 版本应 ≥ MySQL 版本

三、一次性准备:最小权限备份账号

主库创建(物理备份只需连接做短锁与记录位点,不需要 root):Bkp@User2026

CREATE USER 'bkpuser'@'%' IDENTIFIED BY '<强密码>';
GRANT BACKUP_ADMIN, PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'bkpuser'@'%';
GRANT SELECT ON performance_schema.log_status TO 'bkpuser'@'%';
GRANT SELECT ON performance_schema.keyring_component_status TO 'bkpuser'@'%';
GRANT SELECT ON performance_schema.replication_group_members TO 'bkpuser'@'%';
FLUSH PRIVILEGES;

若你的从库会作为备份源(XB_SLAVE_INFO=1),该账号在从库同样需要这些权限, 且主从复制账号需有 REPLICATION SLAVE(用于从库上 START/STOP REPLICA 的由 root 完成,非必需)。

密码传入方式(三选一):

export XB_PASSWORD='<强密码>'                                  # 推荐
# 或在 .env 增加:  XTRABACKUP_PASSWORD=<强密码>

四、备份

cd /opt/mysql    # compose 目录
bash ./xtrabackup_backup.sh

脚本会自动:定位 mysql-master2./data 挂载源与所属网络 → 拉镜像 → 以临时容器执行 xtrabackup --backup --binlog-info=ON(在线)→ 默认立即 --prepare → 生成 BACKUP.metaxtrabackup_binlog_info、sha256 清单 → 按 KEEP_DAYS 清理。

场景 命令
每日全量(主库) bash ./xtrabackup_backup.sh
从从库备份(记录主库位点) XB_SLAVE_INFO=1 bash ./xtrabackup_backup.sh
只备份不 prepare(配合增量时用) PREPARE=0 bash ./xtrabackup_backup.sh
保留 14 天 KEEP_DAYS=14 bash ./xtrabackup_backup.sh
输出到指定目录 XB_BASE=/data/xtrabackups bash ./xtrabackup_backup.sh

crontab(每日 03:00):

0 3 * * * cd /opt/mysql && bash ./xtrabackup_backup.sh >> /opt/mysql/xtrabackup_cron.log 2>&1

输出示例与关键文件

xtrabackups/20260908/mysql-master2_20260908_030001_full/
├── BACKUP.meta                  # 时间/位点/GTID/大小
├── xtrabackup_binlog_info       # 第1行 binlog 文件名+位点; 第2行 GTID(开启GTID时)
├── xtrabackup_checkpoints       # backup_type = full-prepared(LSN 一致点)
├── xtrabackup.sha256            # 完整性清单
└── (ibd/ibdata1/undo_*/redo 等数据文件)
# 同级日志文件(不放进 target-dir):
#   mysql-master2_20260908_030001_full.backup.log / .prepare.log

校验要点:备份完成后务必 grep 'completed OK!' <时间戳>_full.backup.log(脚本已内置并失败退出); 脚本不会删除源库 binlog,主库 binlog 仍须按保留策略另管(做 PITR 用)。

五、恢复(copy-back)与重建从库

# 目标数据目录必须为空/不存在; 典型: 新从库数据目录
bash ./xtrabackup_restore.sh -b ./xtrabackups/20260908/mysql-master2_20260908_030001_full -d ./slave1_data

脚本动作:未 prepare 则先 prepare → copy-back → 删除 auto.cnf(新节点生成新 server_uuid, 主从 + GTID 场景必须)→ chown -R 999:999(官方镜像 mysql 属主)→ 打印接入语句。

然后在 docker-compose.yml 增加从库服务(数据卷指向上面恢复的目录,不能再用空目录初始化):

  mysql-slave1:
    image: mysql:8.0.36
    container_name: mysql-slave1
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}   # 建议与主库一致(备份不覆盖 root)
    command:
      - --server-id=2            # 与主库/其它从库不同
      # 主库 GTID 已开启时再加下面两行(与主库保持一致):
      # - --gtid-mode=ON
      # - --enforce-gtid-consistency=ON
    volumes:
      - ./slave1_data:/var/lib/mysql
    depends_on:
      - mysql
docker compose up -d mysql-slave1

# 等从库起来后, 按 restore 脚本打印的语句接入主从:
#   CHANGE REPLICATION SOURCE TO ... SOURCE_AUTO_POSITION=1(或 SOURCE_LOG_FILE/POS);
#   START REPLICA;
docker exec -e MYSQL_PWD="$MYSQL_ROOT_PASSWORD" mysql-slave1 mysql -uroot \
  -e "SHOW REPLICA STATUS\G"   # 检查 IO/SQL 线程均为 Yes
# 确认追平后再固化只读
docker exec -e MYSQL_PWD="$MYSQL_ROOT_PASSWORD" mysql-slave1 mysql -uroot \
  -e "SET GLOBAL read_only=ON; SET GLOBAL super_read_only=ON;"

若把恢复目录直接作为主库数据目录(故障顶替场景):先 docker compose stop mysql, 恢复到 ./data(需 --force 覆盖且数据目录为空/已备份),再 docker compose up -d mysql

六、备份/恢复演练建议(延续"零数据丢失"要求)

# 每周在隔离容器做一次完整"恢复演练": 恢复 → 启库 → 校验行数 → 丢弃
bash ./xtrabackup_restore.sh -b <最新_full目录> -d ./drill_data
# 临时起一个不占端口/网络的容器(数据目录已含完整数据, 会跳过初始化)
docker run -d --name mysql-drill -e MYSQL_ROOT_PASSWORD="$MYSQL_ROOT_PASSWORD" \
  -v "$(pwd)/drill_data:/var/lib/mysql" mysql:8.0.36
docker exec mysql-drill mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "SELECT COUNT(*) FROM <库>.<表>;"
docker rm -f mysql-drill

七、注意事项

  • 备份容器以 -u 0 运行,只为读 mysql(uid999) 数据文件与写备份目录;备份账号仍是最小权限
  • 数据目录为 bind mount(./data)时,脚本自动挂载同一宿主机路径(只读);为命名卷时自动按卷名挂载。
  • NFS/异步存储上做 --target-dir 可能 fsync 不可靠,备份目录请用本地盘或 sync 挂载的存储。
  • 物理备份目录无法"按库"恢复单表;需要单表恢复请用逻辑备份或 ibd 手工导入。
  • auto.cnf 被删除后,新节点首次启动会生成新 server_uuid,不影响任何数据。
  • 目标目录被 mysqld 占用时 copy-back 必然失败;脚本已要求目标目录为空来兜底。
  • 本方案不采集源库 binlog 文件本身:binlog 保留/PITR 仍需按主库 binlog 策略单独管理。
posted @ 2026-07-21 17:11  追梦$少年  阅读(10)  评论(0)    收藏  举报