编辑
2026-04-26
Mysql数据库
00
请注意,本文编写于 39 天前,最后修改于 39 天前,其中某些信息可能已经过时。

目录

一、两台台服务器部署主从+读写分离(主库只做写,从库做读)
1.配置前准备
2.主库(Master)配置
3.从库(Slave)配置
二、Docker部署MySQL主从复制
1. 创建所有目录
2. 编写 docker-compose.yml
3. 编写主库初始化脚本
4.编写从库自动配置脚本
5. 启动与验证
三、假如从库跟主库数据不一致,怎么把从库恢复跟主库一致
1. 打开终端 A(用于锁表,保持窗口不要关):
2. 打开终端 B(用于备份数据):
3. 回到终端 A,解锁主库:
4.把备份导入从库并重置同步
5.在从库重新配置同步点:

一、两台台服务器部署主从+读写分离(主库只做写,从库做读)

MySQL 主从复制,核心是基于二进制日志(binlog)实现的数据同步:主库把数据变更记录到 binlog 里,从库拉取主库的 binlog,在本地重放,实现主从数据一致,主要用来做读写分离、数据备份、故障容灾。

1.配置前准备

  1. 主库和从库的 MySQL 版本一致,确保网络互通,主库 3306 端口对从库放通;
  2. 主库和从库都开启 binlog,配置唯一的 server_id(主库和从库的 server_id 不能重复,比如主库设 1,从库设 2)。

2.主库(Master)配置

修改 MySQL 的配置文件my.cnf(或my.ini),添加以下核心配置:

ini
[mysqld] # 唯一server_id,不能和从库重复 server_id = 1 # 开启二进制日志 log_bin = mysql-bin # binlog格式,推荐ROW行级模式,数据一致性最好 binlog_format = ROW # 要同步的业务数据库,不写默认同步所有库 binlog_do_db = 要同步的数据库名 # 过滤不同步的系统库 binlog_ignore_db = mysql binlog_ignore_db = information_schema binlog_ignore_db = performance_schema # 主库关闭只读,可正常写入 read_only = 0

重启 MySQL 服务使配置生效:systemctl restart mysqld

在主库创建主从同步专用账号,给从库授权:

sql
-- 创建同步账号,%代表从库任意IP都能访问,也可以指定从库IP提升安全性 CREATE USER 'repl'@'%' IDENTIFIED BY '你的同步密码'; -- 给账号授予主从复制权限 GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'repl'@'%'; -- 刷新权限 FLUSH PRIVILEGES;

锁主库禁止写入,确保备份数据的一致性:

sql
FLUSH TABLES WITH READ LOCK;

查看主库的 binlog 状态,记录 File 和 Position 的值,后面从库配置必须用到:

sql
SHOW MASTER STATUS;

用 mysqldump 备份主库要同步的数据库,导出成 SQL 文件,拷贝到从库上。

解锁主库,恢复写入:

sql
UNLOCK TABLES;

3.从库(Slave)配置

修改 MySQL 的配置文件my.cnf,添加以下核心配置:

ini
[mysqld] # 唯一server_id,必须和主库不同 server_id = 2 # 开启中继日志 relay_log = mysql-relay-bin # 开启只读,普通用户无法写入,超级用户除外 read_only = 1 # 要同步的数据库,和主库保持一致 replicate_do_db = 要同步的数据库名 # 过滤不同步的系统库 replicate_ignore_db = mysql replicate_ignore_db = information_schema replicate_ignore_db = performance_schema

重启 MySQL 服务使配置生效:systemctl restart mysqld

在从库导入主库的备份 SQL 文件,确保主从初始数据一致。

在从库配置主从同步,关联主库:

sql
CHANGE MASTER TO MASTER_HOST='主库的IP地址', MASTER_PORT=3306, MASTER_USER='repl', MASTER_PASSWORD='你设置的同步密码', MASTER_LOG_FILE='主库SHOW MASTER STATUS里的File值', MASTER_LOG_POS=主库SHOW MASTER STATUS里的Position值;

启动主从同步:

sql
START SLAVE;

查看主从同步状态:

sql
SHOW SLAVE STATUS\G

重点看Slave_IO_Running和Slave_SQL_Running两个字段,都是 Yes 就代表主从同步配置成功;Seconds_Behind_Master是 0,代表主从无延迟。

最常见的主从同步故障就是Slave_SQL_Running变成 No,核心原因是主从数据不一致、主键冲突、SQL 语句执行失败。我通常的处理方式是:先跳过错误的事务,再重新同步数据确保主从一致,同时配置主从同步状态的监控告警,提前发现同步异常。

二、Docker部署MySQL主从复制

js
. ├── docker-compose.yml # 下面会写这个文件 ├── master/ │ ├── data/ # 主库数据持久化目录(自动生成) │ └── init/ │ └── init-master.sql # 主库初始化脚本 └── slave/ ├── data/ # 从库数据持久化目录(自动生成) └── init/ └── init-slave.sh # 从库自动配置脚本

1. 创建所有目录

js
mkdir -p master/data master/init slave/data slave/init

2. 编写 docker-compose.yml

js
version: '3.8' services: # 主库 (Master) mysql-master: image: mysql:8.0 container_name: mysql-master environment: MYSQL_ROOT_PASSWORD: root123 # 请自行修改密码 command: > --server-id=1 --log-bin=mysql-bin --binlog-format=ROW --default-authentication-plugin=mysql_native_password volumes: - ./master/data:/var/lib/mysql # 数据持久化 - ./master/init:/docker-entrypoint-initdb.d # 初始化脚本挂载 ports: - "3306:3306" networks: - mysql-repl-net healthcheck: # 健康检查:确保主库完全启动后再启动从库 test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-proot123"] interval: 5s timeout: 10s retries: 5 # 从库 (Slave) mysql-slave: image: mysql:8.0 container_name: mysql-slave environment: MYSQL_ROOT_PASSWORD: root123 # 请自行修改密码 command: > --server-id=2 --relay-log=relay-bin --read-only=1 --default-authentication-plugin=mysql_native_password volumes: - ./slave/data:/var/lib/mysql # 数据持久化 - ./slave/init:/docker-entrypoint-initdb.d # 初始化脚本挂载 ports: - "3307:3306" networks: - mysql-repl-net depends_on: mysql-master: condition: service_healthy # 等待主库健康检查通过 # 自定义网络,保证主从通信稳定 networks: mysql-repl-net: driver: bridge

3. 编写主库初始化脚本

在 master/init/ 目录下创建 init-master.sql

js
-- 创建用于主从复制的专用用户 CREATE USER 'repl'@'%' IDENTIFIED BY 'repl123'; -- 授予复制权限 GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; FLUSH PRIVILEGES;

4.编写从库自动配置脚本

在 slave/init/ 目录下创建 init-slave.sh: (这个脚本会自动去主库拿 Binlog 位置,无需手动操作)

js
#!/bin/bash set -e # 1. 等待主库完全就绪 echo ">>>> 正在等待主库 MySQL 启动..." until mysql -h mysql-master -uroot -proot123 -e "SELECT 1" &> /dev/null; do sleep 2 done # 2. 动态获取主库的 Binlog 文件名和位置 echo ">>>> 正在获取主库状态..." MASTER_STATUS=$(mysql -h mysql-master -uroot -proot123 -e "SHOW MASTER STATUS\G") MASTER_LOG_FILE=$(echo "$MASTER_STATUS" | grep "File:" | awk '{print $2}') MASTER_LOG_POS=$(echo "$MASTER_STATUS" | grep "Position:" | awk '{print $2}') echo ">>>> 检测到主库日志: File=$MASTER_LOG_FILE, Position=$MASTER_LOG_POS" # 3. 配置从库连接 mysql -uroot -proot123 <<-EOSQL STOP SLAVE; CHANGE MASTER TO MASTER_HOST='mysql-master', MASTER_USER='repl', MASTER_PASSWORD='repl123', MASTER_LOG_FILE='$MASTER_LOG_FILE', MASTER_LOG_POS=$MASTER_LOG_POS; START SLAVE; EOSQL echo ">>>> 恭喜!主从复制配置自动完成!"

5. 启动与验证

js
docker-compose up -d

查看日志确认成功:

js
docker-compose logs -f mysql-slave

image.png

验证同步状态:

进入从库数据库检查:

查看 Slave_IO_Running 和 Slave_SQL_Running 是否均为 Yes。

js
docker exec -it mysql-slave mysql -uroot -proot123 -e "SHOW SLAVE STATUS\G"

image.png

在主库写入测试数据

进入主库:

js
docker exec -it mysql-master mysql -uroot -proot123

在 MySQL 命令行中依次执行:

js
-- 1. 创建测试库 CREATE DATABASE test_repl_db; -- 2. 使用该库 USE test_repl_db; -- 3. 创建一张表 CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL ); -- 4. 插入一条数据 INSERT INTO users (name) VALUES ('张三'); -- 5. 查看主库数据 SELECT * FROM users; -- 6. 退出 MySQL exit;

在从库验证数据同步

js
docker exec -it mysql-slave mysql -uroot -proot123

请勿用root用户进行插入操作。

js
-- 1. 查看是否有这个库(应该能看到 test_repl_db) SHOW DATABASES; -- 2. 使用该库 USE test_repl_db; -- 3. 查看数据(应该能看到 '张三' 这条记录) SELECT * FROM users;

三、假如从库跟主库数据不一致,怎么把从库恢复跟主库一致

第一步:在主库锁表并全量备份 这一步的目的是防止备份期间主库又有新数据写入,保证备份是一个一致性的快照。

1. 打开终端 A(用于锁表,保持窗口不要关):

js
# 进入主库容器 docker exec -it mysql-master mysql -uroot -proot123
js
-- 全局锁表(此时主库只能读,不能写) FLUSH TABLES WITH READ LOCK; -- 【关键】查看并记录主库当前的 Binlog 位置(一会儿要用) SHOW MASTER STATUS;

image.png

注意: 执行完 FLUSH TABLES WITH READ LOCK; 后,千万不要退出这个 MySQL 终端,一退出锁就释放了。把这个窗口放一边,去开一个新的终端。 记录下 SHOW MASTER STATUS 的输出,例如:

2. 打开终端 B(用于备份数据):

js
# 在主库执行全量备份,导出所有数据到本地的 backup.sql docker exec mysql-master mysqldump -uroot -proot123 --single-transaction --all-databases --master-data=2 > backup.sql

3. 回到终端 A,解锁主库:

js
-- 解锁 UNLOCK TABLES; -- 退出 exit;

4.把备份导入从库并重置同步

js
# 1. 停止从库的同步线程 docker exec -it mysql-slave mysql -uroot -proot123 -e "STOP SLAVE; RESET SLAVE ALL;" # 2. 将备份文件拷贝到从库容器内 docker cp backup.sql mysql-slave:/tmp/ # 3. 导入数据(这步可能需要几秒钟,取决于数据量) docker exec -i mysql-slave mysql -uroot -proot123 < backup.sql

5.在从库重新配置同步点:

这里需要用到第一步记录的 Binlog 位置(File 和 Position)。

js
docker exec -it mysql-slave mysql -uroot -proot123
js
-- 配置同步点(我已经帮你填好 FilePosition 了) CHANGE MASTER TO MASTER_HOST='mysql-master', MASTER_USER='repl', MASTER_PASSWORD='repl123', MASTER_LOG_FILE='mysql-bin.000004', MASTER_LOG_POS=801; -- 启动同步 START SLAVE; -- 检查状态 SHOW SLAVE STATUS\G

看到 Slave_IO_Running: Yes 和 Slave_SQL_Running: Yes 就成功了!

本文作者:松轩(^U^)

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!