MySQL 主从集群解析:从原理到 Docker 实战部署(2026 年版)
在 2026 年,MySQL 主从复制(Replication)仍是数据库高可用和读写分离的核心方案,尤其在云原生环境中结合 Docker/K8s 使用。本文从原理入手,到Docker 实战部署,适合初学者到中级 DBA。内容基于 MySQL 8.4.x(当前主流 LTS),兼容 5.7/8.0。
一、MySQL 主从复制原理详解
主从复制是 MySQL 的异步复制机制(默认),主库(Master)处理写操作,从库(Slave)同步数据用于读操作。核心目标:数据一致性 + 负载均衡 + 容错。
1. 核心组件与流程(一图秒懂)
主库 (Master) 从库 (Slave)
┌─────────┐ ┌─────────┐
│ 写操作 │ │ IO线程 │ ←── (1) 连接主库,请求 binlog
│ (INSERT │ │ │
│ UPDATE) │ │ Relay │ ←── (2) 中继日志,存 binlog 内容
└────┬────┘ │ Log │
│ │ │
│ binlog (二进制日志) │ SQL线程 │ ←── (3) 执行 relay log 中的 SQL
│ (记录所有变更事件) │ │
└──────────────────────► └─────────┘
- Binlog(二进制日志):主库记录所有 DML/DDL 操作(ROW/STATEMENT/MIXED 格式)。默认 ROW 格式,记录行级变更。
- IO 线程:从库连接主库,复制 binlog 到本地 relay log。
- SQL 线程:从库读取 relay log,执行 SQL 重放变更。
- GTID(全局事务 ID):MySQL 5.6+ 引入,简化复制配置(自动跟踪位置,无需手动指定 binlog 文件/位置)。
流程步骤:
- 主库执行变更 → 记录到 binlog。
- 从库 IO 线程请求主库 binlog(从指定位置开始)。
- 主库 dump 线程发送 binlog 给从库。
- 从库存入 relay log → SQL 线程执行 → 从库数据更新。
2. 复制模式对比(常考)
| 模式 | 描述 | 优缺点 | 适用场景 |
|---|---|---|---|
| 异步 | 默认,主库不等从库确认 | 性能高,但可能丢数据(主库崩溃) | 读多写少、非金融级 |
| 半同步 | 主库等至少一个从库确认 | 平衡性能与一致性,需插件启用 | 中高可用需求 |
| 全同步 | 主库等所有从库确认 | 最强一致性,但性能最低 | 金融、对账场景(少用) |
| 并行复制 | SQL 线程多线程执行(8.0+) | 加速从库追赶主库 | 大量写操作 |
一致性问题:异步模式下,主从延迟(seconds_behind_master)常见原因:网络慢、从库负载高。监控命令:SHOW SLAVE STATUS;。
3. 优势与常见问题
- 优势:读写分离(主写从读);备份/容错;水平扩展。
- 常见问题:
- 延迟:用
pt-heartbeat工具监控。 - 数据不一致:用
pt-table-checksum校验修复。 - 故障切换:手动 failover,或用 MHA/Orchestrator 自动化。
二、Docker 实战部署:一主一从(最小集群)
我们用 Docker Compose 部署(2026 年主流方式),镜像基于官方 mysql:8.4。环境:Docker 25.x+,Compose 2.x+。
1. 准备工作
- 安装 Docker & Docker Compose。
- 创建目录结构:
mysql-cluster/
├── docker-compose.yml
├── master/
│ └── my.cnf
└── slave/
└── my.cnf
2. 配置主从 cnf 文件
master/my.cnf(主库配置):
[mysqld]
server-id=1 # 唯一 ID
log-bin=mysql-bin # 启用 binlog
binlog-format=ROW # ROW 格式
gtid-mode=ON # 启用 GTID
enforce-gtid-consistency=ON # 强制 GTID 一致性
slave/my.cnf(从库配置):
[mysqld]
server-id=2 # 唯一 ID,不同于主
relay-log=relay-log # 启用 relay log
read-only=ON # 从库只读(防止误写)
gtid-mode=ON
enforce-gtid-consistency=ON
3. docker-compose.yml(一键部署)
version: '3.8'
services:
mysql-master:
image: mysql:8.4
container_name: mysql-master
restart: always
environment:
MYSQL_ROOT_PASSWORD: rootpass # 根密码
ports:
- "3306:3306" # 主库端口
volumes:
- ./master/my.cnf:/etc/mysql/conf.d/my.cnf
- master-data:/var/lib/mysql # 数据持久化
mysql-slave:
image: mysql:8.4
container_name: mysql-slave
restart: always
environment:
MYSQL_ROOT_PASSWORD: rootpass
ports:
- "3307:3306" # 从库端口(避免冲突)
volumes:
- ./slave/my.cnf:/etc/mysql/conf.d/my.cnf
- slave-data:/var/lib/mysql
depends_on:
- mysql-master # 启动依赖
volumes:
master-data:
slave-data:
启动命令(在 mysql-cluster 目录):
docker-compose up -d
4. 配置主从复制
- 进入主库容器:
docker exec -it mysql-master mysql -uroot -prootpass
- 主库创建复制用户:
CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'replpass';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;
SHOW MASTER STATUS; -- 记录 GTID_EXECUTED 或 binlog 文件/位置(GTID 模式下可忽略)
- 进入从库容器:
docker exec -it mysql-slave mysql -uroot -prootpass
- 从库配置主库连接(GTID 模式):
CHANGE REPLICATION SOURCE TO
SOURCE_HOST='mysql-master', -- 主库服务名
SOURCE_USER='repl',
SOURCE_PASSWORD='replpass',
SOURCE_AUTO_POSITION=1; -- GTID 自动定位
START SLAVE;
SHOW SLAVE STATUS\G; -- 检查 IO/SQL 线程是否 Running,Seconds_Behind_Master=0 表示同步正常
5. 测试验证
- 主库插入数据:
-- 在主库
CREATE DATABASE testdb;
USE testdb;
CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(50));
INSERT INTO users VALUES (1, 'Alice');
- 从库查询:应该看到相同数据(但从库 read-only,无法写)。
6. 扩展:一主多从 / 级联复制
- 加从库:复制 slave 服务,改 server-id 和端口。
- 级联:从库 A 作为 B 的主(在 A 的 cnf 加 log-slave-updates=1)。
7. 常见 Docker 坑 & 优化
| 问题 | 症状 | 解决方式 |
|---|---|---|
| 网络问题 | 从库连不上主 | 用服务名(如 mysql-master),非 IP |
| 数据卷冲突 | 重启丢失数据 | 用 volumes 持久化 |
| GTID 不一致 | 复制中断 | RESET SLAVE; START SLAVE; |
| 性能瓶颈 | 从库延迟高 | 启用并行复制(slave_parallel_workers=4) |
| 安全 | 暴露端口 | 用 Docker network + 防火墙 |
2026 生产建议:用 Docker Swarm/K8s 扩展;监控用 Prometheus + Grafana;备份用 mysqldump 或 Percona XtraBackup。
这份指南从原理到实战已覆盖 80% 场景。如果你想加半同步、MHA 自动 failover 或Python 脚本自动化,告诉我,我再展开!