主从复制原理
mysql主从复制是指把数据从一个主节点复制到1个或多个从节点,以此来实现数据的同步和备份。
它的原理说的简单一些就是二进制文件的同步。MySQL增删改操作会全部记录在binary log中,当slave节点连接master时,会主动从master处获取最新的bin log文件,之后从节点会执行二进制文件中的sql,这样就和主节点做了同样的操作。
一主一从实现
由于是实验,从资源等方面考虑,此次mysql主从基于docker搭建。
首先来看下docker-compose.yaml 的内容
version: "3"
services:
mysql-master:
image: mysql:5.7
container_name: mysql_master
restart: always
ports:
- 8081:3306
expose:
- 3306
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=luckymoney
volumes:
- mysql-master:/var/lib/mysql
- ./master/mysql.cnf:/etc/mysql/conf.d/mysql.cnf
- ./master/init/:/docker-entrypoint-initdb.d/
mysql-slave:
image: mysql:5.7
container_name: mysql_slave
restart: always
ports:
- 8082:3306
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=luckymoney
volumes:
- mysql-slave:/var/lib/mysql
- ./slave/mysql.cnf:/etc/mysql/conf.d/mysql.cnf
- ./slave/init/:/docker-entrypoint-initdb.d/
volumes:
mysql-master:
mysql-slave:
mysql主从分别对应mysql-master、mysql-slave两个容器。将容器的端口映射到宿主机的8081和8082上。两个mysql的root密码都是root,在启动时都会建一个库名为luckymoney的库。对配置文件和初始化脚本进行了挂载。这里要特别说下初始化脚本的挂载 ./slave/init/:/docker-entrypoint-initdb.d/,通过查看mysql官方的Dockerfile可以知道,mysql容器在启动时会执行目录
/docker-entrypoint-initdb.d下的脚本,所以可以把初始化脚本挂载在这里。
主从配置的重点:
master配置文件
[mysqld]
skip_external_locking
lower_case_table_names=1
skip_host_cache
skip_name_resolve
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
init_connect='SET NAMES utf8mb4'
default-storage-engine=INNODB
#开启二进制日志
log-bin=mysql-bin
#设置server-id,建议使用ip最后3位
server-id=081
## 二进制日志自动删除/过期的天数。默认值为0,表示不自动删除。
expire_logs_days=7
slave配置文件
[mysqld]
skip_external_locking
lower_case_table_names=1
skip_host_cache
skip_name_resolve
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
init_connect='SET NAMES utf8mb4'
default-storage-engine=INNODB
#开启二进制日志
log-bin=mysql-bin
#开启中继日志
relay-log=mysql-relay
#设置server-id,建议使用ip最后3位
server-id=082
# 开启二进制日志功能,以备Slave作为其它Slave的Master时使用
log-bin=mysql-slave-bin
#二进制日志自动删除/过期的天数。默认值为0,表示不自动删除。
expire_logs_days=7
#log_slave_updates表示slave将复制事件写进自己的二进制日志
#log_slave_updates=1
#防止改变数据(除了特殊的线程)
#read_only=1
必要的配置是server-id和开启二进制日志,其中server-id唯一不能重复。
master初始化脚本
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
flush privileges;
这里是创建一个slave 用户并给它分配权限。
slave 初始化脚本
change master to master_host='mysql_master', master_user='slave', master_password='123456', master_port=3306, master_log_file='mysql-bin.000001', master_log_pos= 0, master_connect_retry=30;
master_log_file 是IO thread读到的当前master binlog文件
master_log_pos是IO thread读到的当前master binlog位置
特别要注意,这两个值如果填写错误,则会导致mysql主从同步失败。
那么如何获取这两个值呢?
由于我们的mysql是全新的mysql,数据库中没有数据,那么这两个值就是上面配置中的值。master_log_pos 设置为0,系统会自动匹配。
如果同步失败,在服务启动后j进入master数据库执行命令 show master status;
来获取。
启动mysql服务 docker-compose up -d
,查看docker进程 docker ps
进入slave容器数据库执行命令start slave
开启主从复制
在slave容器数据库中执行show slave status \G;
查看主从同步状态
Slave_IO_Running 和 Slave_SQL_Running 都是Yes,则标识主从同步开启成功。
下面做一个简单的验证
在master上新建一个表test_tbl,创建成功刷新slave库发现slave对应的库也有了这个表
在master test_tbl 插入一条数据
INSERT INTO test_tbl(test_id,test_name) VALUES(1,"风暴烈酒");
刷新slave中的 test_tbl 发现数据已经同步过来了
由于是同一个宿主机下的两个容器,所以速度还是很快的。