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.meta、xtrabackup_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 策略单独管理。

浙公网安备 33010602011771号