MySQL实战篇06: MySQL主从复制Docker实战(下)----读写分离与高可用实践
作者:进击的圆儿
日期:2025年10月10日
标签:MySQL主从复制读写分离高可用实战
📑 目录

🎯 前言:从配置到应用
在上一篇《MySQL主从复制Docker实战(上)》中,我成功配置了1主2从的MySQL集群:
✅ Master:binlog已开启,复制用户已创建
✅ Slave1:IO线程Yes,SQL线程Yes,延迟0秒
✅ Slave2:IO线程Yes,SQL线程Yes,延迟0秒
但是,主从复制配置好了,数据真的能同步吗?读写分离如何实现?
今天的目标:
- 验证数据实时同步
- 配置并测试读写分离
- 分析主从延迟
- 理解三种复制模式的选择
这篇博客记录了我测试主从复制的全过程,包括思考和收获。
🧪 第一部分:数据同步验证
步骤1:在Master创建测试数据库和表
PS D:\pythontest\c++_learn> docker exec mysql-master mysql -uroot -proot123 -e \
"CREATE DATABASE test_replication;
USE test_replication;
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);"
mysql: [Warning] Using a password on the command line interface can be insecure.
✅ 创建成功!
步骤2:在Master插入测试数据
PS D:\pythontest\c++_learn> docker exec mysql-master mysql -uroot -proot123 -e \
"USE test_replication;
INSERT INTO users (id, name) VALUES
(1, 'Alice'),
(2, 'Bob'),
(3, 'Charlie');"
mysql: [Warning] Using a password on the command line interface can be insecure.
✅ 插入成功!
在Master查询验证:
PS D:\pythontest\c++_learn> docker exec mysql-master mysql -uroot -proot123 -e \
"USE test_replication; SELECT * FROM users;"
mysql: [Warning] Using a password on the command line interface can be insecure.
id name created_at
1 Alice 2025-10-10 15:56:52
2 Bob 2025-10-10 15:56:52
3 Charlie 2025-10-10 15:56:52
步骤3:在Slave验证数据同步
Slave1查询:
PS D:\pythontest\c++_learn> docker exec mysql-slave1 mysql -uroot -proot123 -e \
"USE test_replication; SELECT * FROM users;"
mysql: [Warning] Using a password on the command line interface can be insecure.
id name created_at
1 Alice 2025-10-10 15:56:52 ← 和Master完全一致!
2 Bob 2025-10-10 15:56:52
3 Charlie 2025-10-10 15:56:52
Slave2查询:
PS D:\pythontest\c++_learn> docker exec mysql-slave2 mysql -uroot -proot123 -e \
"USE test_replication; SELECT * FROM users;"
mysql: [Warning] Using a password on the command line interface can be insecure.
id name created_at
1 Alice 2025-10-10 15:56:52 ← 和Master完全一致!
2 Bob 2025-10-10 15:56:52
3 Charlie 2025-10-10 15:56:52

🎉 完美!数据已实时同步到2个Slave!
🔒 第二部分:读写分离实战
配置Slave只读模式
为什么需要只读模式?我们稍后解释,先配置:
Slave1设置为只读:
PS D:\pythontest\c++_learn> docker exec mysql-slave1 mysql -uroot -proot123 -e \
"SET GLOBAL read_only=1; SET GLOBAL super_read_only=1;"
mysql: [Warning] Using a password on the command line interface can be insecure.
Slave2设置为只读:
PS D:\pythontest\c++_learn> docker exec mysql-slave2 mysql -uroot -proot123 -e \
"SET GLOBAL read_only=1; SET GLOBAL super_read_only=1;"
mysql: [Warning] Using a password on the command line interface can be insecure.
✅ 配置成功!
参数说明:
read_only=1:普通用户无法写入super_read_only=1:即使是超级用户(root)也无法写入
测试Slave拒绝写入
尝试在Slave1插入数据:

🎉 完美!Slave拒绝了写入操作!
为什么需要只读模式?
读写分离架构:
如果不配置只读模式会怎样?
场景:应用误操作,向Slave写入数据
Slave直接写入:
INSERT INTO users (id, name) VALUES (4, 'David');
↓
Slave本地有id=4的记录
↓
Master通过binlog也插入id=4
↓
主键冲突!数据不一致!💥
配置只读模式:
INSERT操作被拒绝 ✅
强制所有写操作走Master
保证数据一致性
⏱️ 第三部分:主从延迟测试
批量插入数据测试
PS D:\pythontest\c++_learn> docker exec mysql-master mysql -uroot -proot123 -e \
"USE test_replication;
INSERT INTO users (id, name) VALUES
(4, 'David'), (5, 'Eve'), (6, 'Frank'),
(7, 'Grace'), (8, 'Henry'), (9, 'Ivy'), (10, 'Jack');"
mysql: [Warning] Using a password on the command line interface can be insecure.
✅ 插入7条数据成功!
查看Slave延迟

验证Slave1数据:
PS D:\pythontest\c++_learn> docker exec mysql-slave1 mysql -uroot -proot123 -e \
"USE test_replication;
SELECT COUNT(*) as total, MIN(id) as first_id, MAX(id) as last_id FROM users;"
mysql: [Warning] Using a password on the command line interface can be insecure.
total first_id last_id
10 1 10 ← 10条数据全部同步!
为什么延迟是0秒?
Seconds_Behind_Master的含义:
Seconds_Behind_Master = Master当前时间 - Slave正在执行的binlog事件的时间戳
延迟0秒的2种情况:
1. 真的没有延迟(IO和SQL都跟上了)
2. Slave已经追上Master(没有新的binlog可读)
我们的情况:
Read_Master_Log_Pos = Exec_Master_Log_Pos = 2245
↓
已读取 = 已执行 = 完全同步 ✅
主从延迟的影响因素:
- 网络带宽
- Slave硬件性能
- binlog大小
- SQL复杂度
🔀 第四部分:三种复制模式选择
异步复制 vs 半同步 vs 全同步
在学习过程中,我遇到了一个经典场景问题:
| 模式 | Master什么时候返回成功 | 优点 | 缺点 |
|---|---|---|---|
| 异步复制 | 写完自己的binlog就返回 | 快 | 主库宕机可能丢数据 |
| 半同步复制 | 至少1个Slave确认收到binlog | 平衡 | 稍慢 |
| 全同步复制 | 所有Slave都执行完才返回 | 数据最安全 | 很慢 |
不同场景如何选择?
我被问到了3个场景选择题:
Q1:如果你的项目是【微信聊天】,用户发消息必须立即看到"发送成功",你选哪个模式?
我的回答: 异步复制
理由:
- 速度第一,用户体验优先
- 消息丢失可以从客户端重发
- QPS很高,不能让等待影响性能
Q2:如果你的项目是【支付系统】,扣款记录绝对不能丢,你选哪个模式?
我最初的回答: 全同步复制
但经过思考后修正为: 半同步复制 ✅
理由:
全同步的问题:
用户点击"确认支付"
↓
等Master写完binlog
↓
等所有Slave都执行完SQL
↓ (假设有5个Slave,最慢的那个花了3秒)
等所有Slave都确认
↓
页面才显示"支付成功"
问题:
- 如果有1个Slave网络慢,用户要等很久
- 用户以为卡死了,多次点击支付按钮
- 用户体验极差
半同步的优势:
只需要至少1个Slave确认收到binlog
↓
数据已经持久化到2个节点(Master + Slave1)
↓
即使Master宕机,Slave1也有完整数据
↓
数据安全 + 性能可接受 ✅
Q3:如果你的项目是【论坛评论】,偶尔丢一两条评论也能接受,你选哪个模式?
我最初的回答: 半同步复制
但经过思考后修正为: 异步复制 ✅
理由:
既然"能接受丢失",为什么还要用半同步(需要等从库确认)?
异步复制最坏情况:
丢失Master宕机前2-3秒内的评论
论坛场景下:
用户刷新页面重新发一次就行
不影响核心业务
优先保证性能 ✅
我的理解总结
| 场景 | 最佳模式 | 原因 |
|---|---|---|
| 微信聊天 | 异步复制 | 速度第一,消息可重发 |
| 支付系统 | 半同步复制 | 至少1个从库有binlog,主库宕机不丢钱 ✅ |
| 论坛评论 | 异步复制 | 丢失几秒评论可接受,速度优先 |
| 电商订单 | 半同步复制 | 订单数据不能丢,但不能太慢 |
| 日志系统 | 异步复制 | 丢失少量日志可接受,吞吐量优先 |
📝 总结
今天的收获
通过这次读写分离和高可用测试,我掌握了:
✅ 数据同步验证
- Master写入 → Slave自动同步
- Seconds_Behind_Master = 0(实时同步)
✅ 读写分离实战
- Slave只读模式配置(read_only + super_read_only)
- 强制所有写操作走Master,保证数据一致性
✅ 主从延迟理解
- Seconds_Behind_Master的含义
- Read_Master_Log_Pos vs Exec_Master_Log_Pos
✅ 复制模式选择
- 异步:快,可能丢数据
- 半同步:平衡,至少1个Slave确认
- 全同步:最安全,但很慢
- 根据业务场景选择,不是越安全越好!
生产环境最佳实践
-
监控告警
- 监控Seconds_Behind_Master(延迟超过5秒告警)
- 监控Slave_IO_Running和Slave_SQL_Running(不是Yes立即告警)
- 工具:Prometheus + Grafana + Alertmanager
-
高可用方案
- 多Slave(至少2个,最好3个)
- 自动故障切换(MHA、Orchestrator)
- VIP漂移(Keepalived)
-
读写分离方案
- 应用层:代码判断(写走Master,读走Slave)
- 中间件:ProxySQL、MySQL Router
- 框架:ShardingSphere
-
数据备份
- 从Slave备份(不影响Master性能)
- 定期全量备份 + binlog增量备份
- 异地容灾
系列回顾
通过这3篇实战博客,我完整掌握了MySQL主从复制:
博客3:Docker入门
- Docker vs 虚拟机
- 容器、镜像、网络
- 搭建1主2从容器环境
博客4:主从复制配置
- Master配置:binlog、复制用户
- Slave配置:CHANGE MASTER、START SLAVE
- 3个真实问题排查
博客5:读写分离测试
- 数据同步验证
- 只读模式配置
- 三种复制模式选择
参考资料
如果这篇文章对你有帮助,欢迎点赞收藏!
有问题欢迎在评论区讨论~
系列文章:
更多推荐


所有评论(0)