当前位置: 首页 > news >正文

MySQL实战篇05:MySQL主从复制Docker实战(上)——1主2从集群搭建与问题解决

作者:进击的圆儿
日期:2025年10月10日
标签MySQL 主从复制 Docker 实战 问题排查


📑 目录

  • 前言:从Docker容器到主从复制
  • 第一部分:主从复制核心原理
    • 为什么需要主从复制?
    • 主从复制架构
    • 三大线程工作流程
  • 第二部分:Master配置
    • 检查binlog状态
    • 创建复制用户
    • 查看Master状态
  • 第三部分:Slave配置
    • 配置连接参数
    • 启动复制线程
    • 验证复制状态
  • 第四部分:问题排查与解决
    • 问题1:认证插件不兼容
    • 问题2:server_id冲突
    • 问题3:SQL线程执行失败
  • 写在最后

在这里插入图片描述

🎯 前言:从Docker容器到主从复制

在上一篇《Docker入门实战》中,我成功搭建了1主2从的MySQL容器环境:

✅ mysql-master (端口3307)
✅ mysql-slave1 (端口3308)
✅ mysql-slave2 (端口3309)

但此时,这3个MySQL实例是完全独立的,互不影响。

今天的目标:

  • 配置Master和Slave的主从复制关系
  • 实现数据自动同步
  • 解决配置过程中遇到的3个真实问题

这篇博客记录了我从零配置主从复制的全过程,包括踩坑和解决方案。


📚 第一部分:主从复制核心原理

为什么需要主从复制?

在配置之前,先想一个问题:

Q:单机MySQL有什么问题?为什么需要主从复制?

我的思考场景:

假设我的cpp-chat项目上线后:

用户量:100万
总QPS:15000
- 读操作(SELECT):12000(80%)
- 写操作(INSERT/UPDATE):3000(20%)单机MySQL:
- CPU:90%
- 磁盘IO:接近上限

单机MySQL的3大问题:

问题影响解决方案
性能瓶颈读写集中在1台机器,压力大读写分离
单点故障Master宕机,服务全部不可用高可用(Slave提升为Master)
备份影响性能直接备份Master,影响线上服务从Slave备份

主从复制的作用:

Master(1台) → 处理所有写操作↓ binlog复制
Slave(多台) → 处理所有读操作性能提升:3倍(1写+2读)
可用性:Master宕机,Slave顶上

主从复制架构

数据库层
应用层
INSERT/UPDATE/DELETE
写操作
SELECT
读操作
SELECT
读操作
binlog复制
binlog复制
Master mysql-master
处理写操作
Slave1 mysql-slave1
处理读操作
Slave2 mysql-slave2
处理读操作
Web应用

三大线程工作流程

在学习过程中,我遇到了一个关键问题:

Q:主从复制最核心的3个线程分别是什么?它们各自负责什么工作?

我的理解过程:

MasterMaster BinlogMasterBinlog Dump线程SlaveIO线程SlaveRelay LogSlaveSQL线程Slave数据库1. 执行SQL,写入binlog2. 读取binlog3. 请求binlog数据4. 发送binlog数据5. 写入relay log6. 读取relay log7. 重放SQL,写入数据MasterMaster BinlogMasterBinlog Dump线程SlaveIO线程SlaveRelay LogSlaveSQL线程Slave数据库

3个线程详解:

线程位置作用关键点
Binlog Dump线程Master读取binlog,发送给SlaveMaster的"发件人"
IO线程Slave接收binlog,写入relay logSlave的"收件人"
SQL线程Slave读取relay log,重放SQLSlave的"执行者"

我的疑问:

Q:为什么不让Slave直接从Master读binlog并执行,而要搞个relay log中转?

我的理解:

  • 直接的话,如果网络断了或出现故障,从库无法处理
  • relay log拉取到本地后:
    • 本地持久化 → 网络断了也能继续执行
    • 解耦IO和执行 → IO线程专心拉取,SQL线程慢慢执行
    • 故障恢复 → 记录了"已拉取位置"和"已执行位置"

🔧 第二部分:Master配置

步骤1:检查binlog状态

理解binlog的作用:

Q:如果Master没开binlog,会怎样?

我的回答:

  • IO线程无法读取binlog
  • 导致从库没有办法去执行SQL线程
  • SQL重放失败

结论:binlog是主从复制的"数据源",没有它复制无法进行!


进入Master容器:

# 进入Master容器
PS D:\pythontest\c++_learn> docker exec -it mysql-master bash
bash-5.1## 检查binlog状态
bash-5.1# mysql -uroot -proot123 -e "SHOW VARIABLES LIKE 'log_bin';"
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | ON    |  ← binlog已开启 ✅
+---------------+-------+

在这里插入图片描述

MySQL 8.0默认已经开启binlog!


步骤2:创建复制用户

在创建之前,我遇到了一个问题:

Q:为什么要单独创建一个"复制用户",不能直接用root吗?

我最初的回答: “为了安全性?”

深入理解后:

这是最小权限原则

root用户权限:
├─ 创建/删除数据库  ✅
├─ 创建/删除用户    ✅
├─ 修改配置         ✅
├─ 读取所有数据     ✅
└─ SHUTDOWN服务器   ✅  ← 超级权限!复制用户权限:
└─ REPLICATION SLAVE  ← 只能读取binlog,仅此而已!

安全场景:

如果Slave服务器被黑客攻破:用root(危险):黑客拿到root密码↓连接Master↓DROP DATABASE production;  💥SHUTDOWN;                  💥用复制用户(安全)✅:黑客拿到复制用户密码↓连接Master↓只能读binlog,无法执行任何破坏操作 ✅

创建复制用户:

# 创建用户
bash-5.1# mysql -uroot -proot123 -e "CREATE USER 'repl'@'%' IDENTIFIED BY 'repl123';"
mysql: [Warning] Using a password on the command line interface can be insecure.# 授予复制权限
bash-5.1# mysql -uroot -proot123 -e "GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';"
mysql: [Warning] Using a password on the command line interface can be insecure.

没有报错就是成功!

参数说明:

  • 'repl'@'%':用户名repl@'%'表示允许从任何主机连接
  • 为什么用@'%'?因为我们有Slave1和Slave2,用%可以让所有Slave都能连接

步骤3:查看Master状态

在这里插入图片描述

关键信息:

  • File: binlog.000002 = Master当前的binlog文件名
  • Position: 689 = binlog的当前位置

这两个值非常重要!Slave连接时需要告诉Master:

“我从binlog.000002的第689个字节开始读”


退出Master容器:

bash-5.1# exit
exit
PS D:\pythontest\c++_learn>

🔄 第三部分:Slave配置

步骤1:配置连接参数

在配置之前,先理解原理:

Q:Slave要连接Master,需要告诉MySQL哪些信息?

我的思考:

Master信息:

  • 容器名:mysql-master
  • 复制用户:repl
  • 用户密码:repl123
  • binlog文件:binlog.000002
  • binlog位置:689

Q:如果不告诉Slave"从binlog.000002的689位置开始读",会发生什么?

我的回答:

  • 不告诉的话可能会乱读,大概率从头开始
  • 那么可能会导致冲突
  • 不能从头读,可能有很多东西是相同的会重复,引发SQL冲突

场景示例:

Master的binlog历史记录:
binlog.000001:位置0-1000:CREATE DATABASE test;位置1001-2000:CREATE TABLE users(id INT);位置2001-3000:INSERT INTO users VALUES(1);binlog.000002:位置0-688:系统初始化操作位置689:← 我们的起点(从这里开始同步)如果Slave从头读(位置0):↓
重复执行CREATE DATABASE test; ❌
重复执行CREATE TABLE users; ❌
重复执行INSERT VALUES(1); ❌↓
主键冲突、数据重复!

进入Slave1容器:

PS D:\pythontest\c++_learn> docker exec -it mysql-slave1 bash
bash-5.1#

执行CHANGE MASTER命令:

bash-5.1# mysql -uroot -proot123 -e "CHANGE MASTER TO \MASTER_HOST='mysql-master', \MASTER_USER='repl', \MASTER_PASSWORD='repl123', \MASTER_LOG_FILE='binlog.000002', \MASTER_LOG_POS=689;"
mysql: [Warning] Using a password on the command line interface can be insecure.

配置成功!


步骤2:启动复制线程

bash-5.1# mysql -uroot -proot123 -e "START SLAVE;"
mysql: [Warning] Using a password on the command line interface can be insecure.

启动成功!


步骤3:验证复制状态

bash-5.1# mysql -uroot -proot123 -e "SHOW SLAVE STATUS\G" | grep -E "Slave_IO_Running|Slave_SQL_Running|Seconds_Behind_Master"
mysql: [Warning] Using a password on the command line interface can be insecure.Master_Log_File: binlog.000002Read_Master_Log_Pos: 689Slave_IO_Running: Connecting  ← 正在连接中Slave_SQL_Running: Yes        ← SQL线程正常 ✅Seconds_Behind_Master: NULL

看到 Connecting 表示IO线程正在尝试连接Master…

等待几秒后再次检查:

bash-5.1# mysql -uroot -proot123 -e "SHOW SLAVE STATUS\G" | grep -E "Slave_IO_Running|Slave_SQL_Running|Last_IO_Error"
mysql: [Warning] Using a password on the command line interface can be insecure.Slave_IO_Running: ConnectingSlave_SQL_Running: YesLast_IO_Error: Error connecting to source 'repl@mysql-master:3306'. 
This was attempt 2/86400, with a delay of 60 seconds between attempts. 
Message: Authentication plugin 'caching_sha2_password' reported error: 
Authentication requires secure connection.

🚨 出现错误了!


🐛 第四部分:问题排查与解决

问题1:认证插件不兼容

错误信息:

Authentication plugin 'caching_sha2_password' reported error: 
Authentication requires secure connection.

问题分析:

MySQL 8.0的认证问题:

MySQL 8.0默认使用 caching_sha2_password 认证插件↓
这个插件要求"安全连接"(SSL加密)↓
但我们没有配置SSL证书↓
Slave无法连接Master ❌

解决方案:修改repl用户的认证方式

步骤1:退出Slave,回到宿主机

bash-5.1# exit
exit
PS D:\pythontest\c++_learn>

步骤2:修改Master上的repl用户认证方式

PS D:\pythontest\c++_learn> docker exec mysql-master mysql -uroot -proot123 \-e "ALTER USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'repl123';"
mysql: [Warning] Using a password on the command line interface can be insecure.

修改成功!

步骤3:重启Slave复制线程

PS D:\pythontest\c++_learn> docker exec mysql-slave1 mysql -uroot -proot123 \-e "STOP SLAVE; START SLAVE;"
mysql: [Warning] Using a password on the command line interface can be insecure.

步骤4:再次检查状态

PS D:\pythontest\c++_learn> docker exec mysql-slave1 mysql -uroot -proot123 \-e "SHOW SLAVE STATUS\G" | Select-String "Slave_IO_Running|Slave_SQL_Running|Last_IO_Error"
mysql: [Warning] Using a password on the command line interface can be insecure.Slave_IO_Running: No   ← 还是有问题!Slave_SQL_Running: YesLast_IO_Error: Fatal error: The replica I/O thread stops because 
source and replica have equal MySQL server ids...

🚨 新的错误出现了!


问题2:server_id冲突

错误信息:

Fatal error: The replica I/O thread stops because source and replica 
have equal MySQL server ids; these ids must be different

问题分析:

Master的server_id: 1
Slave的server_id: 1  ← 相同了!MySQL要求:主从复制中,每个MySQL实例必须有唯一的server_id就像身份证号,不能重复!

解决方案:修改Slave的server_id

步骤1:检查Master的server_id

PS D:\pythontest\c++_learn> docker exec mysql-master mysql -uroot -proot123 \-e "SHOW VARIABLES LIKE 'server_id';"
mysql: [Warning] Using a password on the command line interface can be insecure.
Variable_name   Value
server_id       1

步骤2:修改Slave1的server_id为2

PS D:\pythontest\c++_learn> docker exec mysql-slave1 mysql -uroot -proot123 \-e "SET GLOBAL server_id=2;"
mysql: [Warning] Using a password on the command line interface can be insecure.

修改成功!

步骤3:重启Slave复制线程

PS D:\pythontest\c++_learn> docker exec mysql-slave1 mysql -uroot -proot123 \-e "STOP SLAVE; START SLAVE;"
mysql: [Warning] Using a password on the command line interface can be insecure.

步骤4:检查状态

PS D:\pythontest\c++_learn> docker exec mysql-slave1 mysql -uroot -proot123 \-e "SHOW SLAVE STATUS\G" | Select-String "Slave_IO_Running|Slave_SQL_Running"
mysql: [Warning] Using a password on the command line interface can be insecure.Slave_IO_Running: Yes  ← IO线程正常了! ✅Slave_SQL_Running: No   ← SQL线程停止了! ❌

🚨 又有新问题!


问题3:SQL线程执行失败

错误信息:

PS D:\pythontest\c++_learn> docker exec mysql-slave1 mysql -uroot -proot123 \-e "SHOW SLAVE STATUS\G" | Select-String "Last_SQL_Error"
mysql: [Warning] Using a password on the command line interface can be insecure.Last_SQL_Error: Coordinator stopped because there were error(s) 
in the worker(s). The most recent failure being: Worker 1 failed executing 
transaction 'ANONYMOUS' at source log binlog.000002, end_log_pos 971...

问题分析:

这可能是因为之前的配置冲突导致的SQL执行错误。


解决方案:重置Slave,从最新位置开始

步骤1:查看Master当前状态

PS D:\pythontest\c++_learn> docker exec mysql-master mysql -uroot -proot123 \-e "SHOW MASTER STATUS;"
mysql: [Warning] Using a password on the command line interface can be insecure.
File    Position        Binlog_Do_DB    Binlog_Ignore_DB        Executed_Gtid_Set
binlog.000002   971

Master当前位置:binlog.000002, Position: 971

步骤2:重置Slave并重新配置

PS D:\pythontest\c++_learn> docker exec mysql-slave1 mysql -uroot -proot123 -e \"STOP SLAVE; RESET SLAVE; CHANGE MASTER TO MASTER_HOST='mysql-master', MASTER_USER='repl', MASTER_PASSWORD='repl123', MASTER_LOG_FILE='binlog.000002', MASTER_LOG_POS=971; START SLAVE;"
mysql: [Warning] Using a password on the command line interface can be insecure.

重置并重新配置成功!

步骤3:验证状态(期待双Yes!)

PS D:\pythontest\c++_learn> docker exec mysql-slave1 mysql -uroot -proot123 \-e "SHOW SLAVE STATUS\G" | Select-String "Slave_IO_Running|Slave_SQL_Running|Seconds_Behind_Master"
mysql: [Warning] Using a password on the command line interface can be insecure.Slave_IO_Running: Yes   ← IO线程正常 ✅Slave_SQL_Running: Yes   ← SQL线程正常 ✅Seconds_Behind_Master: 0     ← 主从延迟0秒 ✅

在这里插入图片描述

🎉 完美!Slave1主从复制成功启动!


快速配置Slave2

有了Slave1的经验,Slave2配置就很简单了:

PS D:\pythontest\c++_learn> docker exec mysql-slave2 mysql -uroot -proot123 -e \"SET GLOBAL server_id=3; CHANGE MASTER TO MASTER_HOST='mysql-master', MASTER_USER='repl', MASTER_PASSWORD='repl123', MASTER_LOG_FILE='binlog.000002', MASTER_LOG_POS=971; START SLAVE;"
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 "SHOW SLAVE STATUS\G" | Select-String "Slave_IO_Running|Slave_SQL_Running|Seconds_Behind_Master"
mysql: [Warning] Using a password on the command line interface can be insecure.Slave_IO_Running: Yes   ← IO线程正常 ✅Slave_SQL_Running: Yes   ← SQL线程正常 ✅Seconds_Behind_Master: 0     ← 主从延迟0秒 ✅

🎉 Slave2也成功了!1主2从集群完全配置好了!


📝 写在最后

今天的收获

通过这次主从复制实战,我掌握了:

核心概念

  • 主从复制的3大线程:Binlog Dump、IO、SQL
  • binlog和relay log的作用
  • server_id的重要性

实战技能

  • 配置Master:开启binlog、创建复制用户
  • 配置Slave:CHANGE MASTER、START SLAVE
  • 排查问题:查看SHOW SLAVE STATUS

问题解决能力

  • 问题1:认证插件不兼容 → 修改为mysql_native_password
  • 问题2:server_id冲突 → 设置唯一的server_id
  • 问题3:SQL线程执行失败 → RESET SLAVE重新开始

遇到问题时的排查思路

IO线程
SQL线程
认证错误
连接错误
server_id冲突
SQL执行错误
数据冲突
发现问题:
Slave_IO_Running/Slave_SQL_Running不是Yes
哪个线程有问题?
查看Last_IO_Error
查看Last_SQL_Error
错误类型
检查用户密码/认证插件
检查网络/Master地址
修改server_id
错误类型
检查binlog位置是否正确
RESET SLAVE重新开始

生产环境注意事项

配置项测试环境生产环境
server_id临时设置写入配置文件(永久生效)
复制用户简单密码强密码 + 定期轮换
SSL连接未配置建议开启(数据加密)
binlog格式默认ROW根据场景选择(ROW/STATEMENT/MIXED)
监控手动检查自动监控(Prometheus + Grafana)

下一步计划

主从复制已经配置好了,下一步要做的是:

  1. 验证数据同步

    • Master写入数据
    • Slave查询验证
  2. 测试读写分离

    • 配置Slave为只读模式
    • 测试Slave拒绝写操作
  3. 主从延迟测试

    • 批量插入数据
    • 观察Seconds_Behind_Master
  4. 三种复制模式选择

    • 异步复制 vs 半同步 vs 全同步
    • 不同场景的选择策略

这些内容将在下一篇博客《MySQL主从复制Docker实战(下)》中详细记录!


参考资料

  • MySQL官方文档 - Replication
  • MySQL官方文档 - CHANGE MASTER TO
  • Docker MySQL镜像

如果这篇文章对你有帮助,欢迎点赞收藏!
有问题欢迎在评论区讨论~


系列文章:

  • 上一篇:《Docker入门实战:从零搭建MySQL容器环境》
  • 下一篇:《MySQL主从复制Docker实战(下):读写分离与高可用实践》
http://www.dtcms.com/a/470145.html

相关文章:

  • 金融网站建设方案ppt模板重庆建设厅官网
  • 从源码优化外卖配送系统:算法调度、智能推荐与数据分析应用
  • 百宝图建设工程电子网站网络公司如何建网站
  • vscode 远程管理docker时,提示权限不足无法获取容器列表问题
  • 定制营销型网站什么意思wordpress建立移动m站
  • 石家庄无极网站建设网站开发实战项目
  • AI智能体(Agent)大模型入门【12】--基于llamaindex框架,fastapi框架实现大模型聊天基于mysql存储的历史对话进行聊天
  • 射频噪声干扰、调频调幅干扰仿真及SAR成像实现
  • 基于 Azure API Management 的企业级 AI 服务网关实现
  • MATLAB绘制9种最新的混沌系统
  • 潍坊网站建设潍坊佛山网站快速排名提升
  • 基于MATLAB的MIT-BIH ECG数据PQRST波定位实现
  • 物联网平台软件知道一个网站怎么知道是谁做的百度优化
  • MATLAB绘制多种混沌系统
  • 通信协议总结
  • starrocks表模型
  • 中国重庆网站建设vs2008不能新建网站
  • 个人二级网站怎么做任房保障和城乡建设局网站
  • 企业网站主页设计图微信小程序超市平台
  • 《MCU职位》面试问题
  • 用于化学绘图与IUPAC命名:InDraw 软件的基本使用指南
  • 网页设计与网站建设设计报告建设银行网站查余额
  • 网站meta 优化建议做网站的程序员进什么公司好
  • 【电路】电容的频率特性与通阻范围计算详解
  • LLM 笔记 —— 05 有关影像的生成式 AI
  • MySQL字符集引起的锁表、唯一索引重复问题
  • 算法6.0
  • 【C 学习】12.1-函数基础
  • 11.程序地址空间_2
  • Java的方法重写/覆盖