docker搭建mysql主从集群
MySQL主从同步原理
主从同步通过主库(Master)记录变更日志,从库(Slave)读取并重放日志实现数据复制,保障数据冗余和高可用性。
主从架构示意
表格:MySQL主从复制组件及作用
组件 | 作用 |
---|---|
Binary Log | 主库记录所有数据变更的日志,是主从同步的核心。 |
I/O线程 | 从库的线程,负责从主库获取Binary Log并写入Relay Log。 |
SQL线程 | 从库的线程,负责读取Relay Log并执行其中的SQL语句。 |
Relay Log | 从库本地存储主库Binary Log的中间日志,用于SQL线程重放。 |
MySQL主从复制流程
- 主节点MySQL接收到数据变更时,将事务写入Binary Log。
- Binary Log通过多线程机制被读取并发送到从节点。
- 从节点的I/O线程接收Binary Log内容,写入本地Relay Log。
- 从节点的SQL线程读取Relay Log中的SQL语句并执行,最终将数据变更应用到从节点MySQL。
主从同步方式对比
同步方式 | 原理 | 优点 | 缺点 |
---|---|---|---|
异步复制 (Asynchronous) | 主库提交事务后立即返回,不等待从库确认 | 性能高,延迟低 | 从库可能滞后,数据一致性较差 |
半同步复制 (Semi-Synchronous) | 主库提交事务后,至少等待一个从库确认接收日志 | 数据一致性更好 | 性能略有下降 |
全同步复制 (Synchronous) | 主库提交事务后,等待所有从库确认接收日志 | 数据一致性最好 | 性能较低 |
增强半同步复制 (Rising-Semi-Sync) | 对半同步复制的改进,原理类似,主要解决幻读问题 | 数据一致性更好,解决幻读问题 | 性能略有下降 |
部署:
编辑Master目录下的Dockerfile:
FROM mysql:5.7.36
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
编辑slave目录下的Dockerfile:
FROM mysql:5.7.36
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY ./slave/slave.sql /docker-entrypoint-initdb.d
编辑slave.sql
change master to master_host='mysql-master',
master_user='root',master_password='root',master_port=3306;
start slave;
在主目录mysql下创建docker-compose.yml文件进行编辑:
name: mysqlservices:mysql-master:build:context: ./dockerfile: ./master/Dockerfileimage: mysqlmaster:1.0restart: alwayscontainer_name: mysql-mastervolumes:- ./mastervarlib:/var/lib/mysqlports:- 8080:3306environment:MYSQL_ROOT_PASSWORD: rootprivileged: truecommand: ['--server-id=1','--log-bin=master-bin','--binlog-ignore-db=mysql','--binlog_cache_size=256M','--binlog_format=mixed','--lower_case_table_names=1','--character-set-server=utf8','--collation-server=utf8_general_ci']mysql-slave:build:context: ./dockerfile: ./slave/Dockerfileimage: mysqlslave:1.0restart: alwayscontainer_name: mysql-slavevolumes:- ./slavevarlib:/var/lib/mysqlports:- 8081:3306environment:MYSQL_ROOT_PASSWORD: rootprivileged: truecommand: ['--server-id=2','--relay_log=slave-relay','--lower_case_table_names=1','--character-set-server=utf8','--collation-server=utf8_general_ci']depends_on:- mysql-mastermysql-slave2:build:context: ./dockerfile: ./slave/Dockerfileimage: mysqlslave:1.0restart: alwayscontainer_name: mysql-slave2volumes:- ./slavevarlib2:/var/lib/mysqlports:- 8082:3306environment:MYSQL_ROOT_PASSWORD: rootprivileged: truecommand: ['--server-id=3','--relay_log=slave-relay','--lower_case_table_names=1','--character-set-server=utf8','--collation-server=utf8_general_ci']depends_on:- mysql-master
mysql-master:restart:指定容器的重启策略。
always 表示无论容器因何种原因退出,Docker 都会尝试重新启动它。volume:用于将主机目录挂载到容器中
./mastervarlib 是主机上的目录,/var/lib/mysql 是容器中 MySQL 默认的数据存储路径。
作用:将 MySQL 的数据存储在主机上,确保容器重启或删除后数据不会丢失。envirnment:设置环境变量
MYSQL_ROOT_PASSWORD: root 指定 MySQL 的 root 用户密码为 root。
privileged:设置容器以特权模式运行command:
设置 MySQL 服务器的唯一 ID,主从复制中必须指定,且每个服务器的 ID 必须唯一
启用二进制日志(Binary Log),日志文件前缀为 master-bin,记录主库的写操作
指定忽略mysql系统数据库的二进制日志记录
设置二进制日志缓存的大小为 256MB
设置二进制日志的格式为 mixed
设置表名不区分大小写
设置服务器的默认字符集为 utf8
设置服务器的默认排序规则为 utf8_general_cimysql-slave1:depends-on:指定服务之间的依赖关系
mysql-slave 服务依赖于 mysql-master 服务
确保在启动 mysql-slave 之前,mysql-master 服务已经启动
启动:
docker compose up -d
查看主从复制状态的命令
MySQL命令来检查主从复制状态。以下是完整的操作流程:
docker exec -it mysql-slave mysql -uroot -proot -e "SHOW SLAVE STATUS\G"
这条命令会直接输出从库的复制状态。关键字段包括:
Slave_IO_Running
(IO线程状态)Slave_SQL_Running
(SQL线程状态)Seconds_Behind_Master
(主从延迟秒数)Last_IO_Error
/Last_SQL_Error
(错误信息)
核对以下关键指标:
- 两个线程必须显示为
Yes
:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Seconds_Behind_Master
应为0或较小的数值Master_Log_File
与Read_Master_Log_Pos
应与主库的SHOW MASTER STATUS
输出匹配
测试:
在主库上:
docker exec -it mysql-master bashcreate database test;mysql> use test;
Database changed
mysql> create table users(sno int,sname varchar(20));
Query OK, 0 rows affected (0.03 sec)mysql> insert into users values (1,'xixi');
Query OK, 1 row affected (0.02 sec)mysql> insert into users values (2,'haha');
Query OK, 1 row affected (0.01 sec)
在从库上:
mysql> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -ADatabase changed
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| users |
+----------------+
1 row in set (0.00 sec)mysql> select * from users;
+------+-------+
| sno | sname |
+------+-------+
| 1 | xixi |
| 2 | haha |
+------+-------+
2 rows in set (0.00 sec)