1. 项目概述
MySQL主从复制是企业级数据库架构中的基础配置方案,而Docker容器化部署正逐渐成为现代运维的标准实践。将两者结合既能发挥容器化的快速部署优势,又能实现传统数据库的高可用特性。我在最近的生产环境迁移项目中,完整实践了基于Docker的MySQL 8主从复制方案,过程中踩遍了几乎所有可能的坑——从网络配置冲突到GTID同步异常,从权限设置错误到字符集不匹配。本文将呈现经过实战检验的完整配置流程,包含那些官方文档不会告诉你的细节陷阱。
2. 环境准备与拓扑设计
2.1 容器网络规划
主从复制对网络延迟敏感,推荐使用自定义bridge网络而非默认的docker0网络。以下创建专用网络的命令包含MTU优化参数:
docker network create \ --driver bridge \ --subnet=172.28.0.0/16 \ --gateway=172.28.5.1 \ --opt "com.docker.network.bridge.mtu=1500" \ mysql-replication-net注意:MTU值需要与宿主机的物理网卡保持一致(通过
ifconfig查看),容器间巨型帧传输失败是常见同步中断原因。
2.2 存储卷配置
数据持久化必须使用volume而非bind mount,避免权限问题:
docker volume create mysql-master-data docker volume create mysql-slave-data验证volume路径是否符合MySQL的datadir要求:
docker run --rm -v mysql-master-data:/var/lib/mysql alpine \ ls -ld /var/lib/mysql3. 主库配置实战
3.1 主库容器启动
使用官方mysql:8.0镜像启动主库,关键参数包括server-id和log-bin:
docker run -d --name mysql-master \ --network mysql-replication-net \ --ip 172.28.5.10 \ -v mysql-master-data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=Master@123 \ -e MYSQL_ROOT_HOST='%' \ mysql:8.0 \ --server-id=1 \ --log-bin=mysql-bin \ --binlog-format=ROW \ --binlog-row-image=FULL \ --sync_binlog=1 \ --gtid-mode=ON \ --enforce-gtid-consistency=ON3.2 主库关键配置解析
- binlog-row-image=FULL:确保所有列数据都写入binlog,避免从库更新时因缺少字段报错
- sync_binlog=1:每次事务提交都同步binlog到磁盘,牺牲部分性能保证数据安全
- GTID模式:全局事务标识符能简化故障转移和位置追踪
3.3 创建复制账户
进入主库容器执行:
CREATE USER 'repl'@'172.28.5.%' IDENTIFIED WITH mysql_native_password BY 'Repl@123'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'172.28.5.%'; ALTER USER 'repl'@'172.28.5.%' IDENTIFIED WITH mysql_native_password BY 'Repl@123';血泪教训:MySQL 8默认使用caching_sha2_password插件,必须显式指定mysql_native_password,否则从库连接会报"Authentication plugin error"。
4. 从库配置与同步启动
4.1 从库容器启动
docker run -d --name mysql-slave \ --network mysql-replication-net \ --ip 172.28.5.11 \ -v mysql-slave-data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=Slave@123 \ mysql:8.0 \ --server-id=2 \ --log-bin=mysql-bin \ --binlog-format=ROW \ --gtid-mode=ON \ --enforce-gtid-consistency=ON \ --skip-slave-start4.2 配置主从连接
获取主库GTID位置:
SHOW MASTER STATUS\G -- 记录Executed_Gtid_Set值如:3a59f153-4f4e-11ec-9a1e-0242ac110002:1-10在从库执行CHANGE MASTER命令:
CHANGE MASTER TO MASTER_HOST='172.28.5.10', MASTER_USER='repl', MASTER_PASSWORD='Repl@123', MASTER_AUTO_POSITION=1; START SLAVE;4.3 验证复制状态
关键指标检查:
SHOW SLAVE STATUS\G -- Slave_IO_Running: Yes -- Slave_SQL_Running: Yes -- Seconds_Behind_Master: 0 -- Retrieved_Gtid_Set与Executed_Gtid_Set应与主库匹配5. 深度踩坑实录
5.1 时区不一致导致timestamp字段异常
现象:主库插入的timestamp字段在从库显示不同值 解决方案:
# 启动容器时统一时区 -e TZ=Asia/Shanghai --default-time-zone='+8:00'5.2 大事务导致复制中断
错误日志:"Worker 1 failed executing transaction..." 处理方法:
-- 主库配置 SET GLOBAL binlog_group_commit_sync_delay = 100; SET GLOBAL binlog_group_commit_sync_no_delay_count = 10; -- 从库恢复 STOP SLAVE; SET GLOBAL sql_slave_skip_counter=1; START SLAVE;5.3 容器重启后复制失效
根本原因:从库的master.info未持久化 解决方案:
# 创建专用配置卷 docker volume create mysql-slave-conf # 启动时挂载配置文件 -v mysql-slave-conf:/etc/mysql/conf.d \ --relay-log=slave-relay-bin \ --relay-log-index=slave-relay-bin.index6. 完整验证方案
6.1 基础数据同步测试
-- 主库操作 CREATE DATABASE replica_test; USE replica_test; CREATE TABLE users(id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50)); INSERT INTO users(name) VALUES('测试用户'); -- 从库验证 SELECT * FROM replica_test.users;6.2 故障转移演练
模拟主库宕机:
docker stop mysql-master -- 从库提升为主库 STOP SLAVE; RESET SLAVE ALL; SET GLOBAL read_only=OFF;6.3 延迟压力测试
使用sysbench制造负载:
sysbench oltp_read_write \ --db-driver=mysql \ --mysql-host=172.28.5.10 \ --mysql-user=root \ --mysql-password=Master@123 \ --mysql-db=replica_test \ --tables=5 \ --table-size=100000 \ --time=300 \ --threads=16 \ --report-interval=10 \ run监控从库延迟:
-- 在从库执行 SHOW SLAVE STATUS\G -- 观察Seconds_Behind_Master波动7. 性能优化建议
7.1 容器资源限制
# 主库容器启动时添加 --memory=4g --memory-swap=4g \ --cpus=2 \ --blkio-weight=5007.2 MySQL参数调优
主库my.cnf追加:
innodb_flush_log_at_trx_commit=1 innodb_buffer_pool_size=2G binlog_group_commit_sync_delay=100 binlog_group_commit_sync_no_delay_count=10从库my.cnf追加:
read_only=ON slave_parallel_workers=4 slave_parallel_type=LOGICAL_CLOCK7.3 监控方案
推荐使用Prometheus+mysqld_exporter+Grafana组合,关键监控指标:
- 复制延迟(seconds_behind_master)
- IO/SQL线程状态(slave_io_running, slave_sql_running)
- 网络往返时间(rtt)