工作原理
MySQL Replication,可以实现将数据从一台库服务器( master)复制到一 台或多台数据库服务器 (slave)。默认情况下属于异步复制,无需维持长连接,通过配置,可以复制所有的库或者几个甚至中一些表,这个功能是 MySQL 内建的,本身自带的。
-
Replication的作用
- Fail Over
故障切换 - Backup Server
备份服务,无法对 SQL 语句执行产生的故障恢复,有限备份 - High Performance
高性能,可以多台 slave, 实现读写分离
- Fail Over
-
Replication 工作原理
整体上来说,复制有 3 个步骤:- master 将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events)
- slave 将 master 的 binary log events 拷贝到它的中继日志(relay log)
- slave 重做中继日志中的事件,修改 salve 上的数据
安装与配置
Docker-compose安装Mysql
version: "3"
networks:
default:
external:
name: hm-network
services:
mysql5.7.31_master:
image: mysql:5.7.31
container_name: hm-mysql5.7.31-master
restart: always
ports:
- 3307:3306
volumes:
- "./mysql5.7.31_master/data:/var/lib/mysql"
- "./mysql5.7.31_master/conf/my.cnf:/etc/mysql/my.cnf"
- "./mysql5.7.31_master/log:/var/log/mysql"
- "./mysql5.7.31_master/init:/docker-entrypoint-initdb.d/"
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: root
MYSQL_ROOT_HOST: "%"
deploy:
resources:
limits:
memory: 1G
mysql5.7.31_slave1:
image: mysql:5.7.31
container_name: hm-mysql5.7.31-slave1
restart: always
ports:
- 3308:3306
volumes:
- "./mysql5.7.31_slave1/data:/var/lib/mysql"
- "./mysql5.7.31_slave1/conf/my.cnf:/etc/mysql/my.cnf"
- "./mysql5.7.31_slave1/log:/var/log/mysql"
- "./mysql5.7.31_slave1/init:/docker-entrypoint-initdb.d/"
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: root
MYSQL_ROOT_HOST: "%"
deploy:
resources:
limits:
memory: 1G
mysql5.7.31_slave2:
image: mysql:5.7.31
container_name: hm-mysql5.7.31-slave2
restart: always
ports:
- 3309:3306
volumes:
- "./mysql5.7.31_slave2/data:/var/lib/mysql"
- "./mysql5.7.31_slave2/conf/my.cnf:/etc/mysql/my.cnf"
- "./mysql5.7.31_slave2/log:/var/log/mysql"
- "./mysql5.7.31_slave2/init:/docker-entrypoint-initdb.d/"
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: root
MYSQL_ROOT_HOST: "%"
deploy:
resources:
limits:
memory: 1G
配置
主master配置文件my.cnf
#Server ID,一般设置成IP地址的最后一位
server_id=100
##开启log bin,名字最好有意义用来区分
log-bin=master-bin
##需要进行复制的数据库,可以指定数据库,这里我注释掉不用
binlog-do-db=ds_0
binlog-do-db=ds_1
##不需要备份的数据库,可以设置多个数据库,一般不会同步mysql这个库
binlog-ignore-db=mysql
binlog-ignore-db=information_schema
binlog-ignore-db=performance_schema
# 跳过所有的错误,继续执行复制操作
slave-skip-errors = all
从slave配置文件my.cnf
# 从数据库端ID号
server_id = 101
log-bin = master-bin
relay_log=replicas-mysql-relay-bin
# # 指定slave要忽略复制哪个库
binlog-ignore-db=mysql
binlog-ignore-db=information_schema
binlog-ignore-db=performance_schema
# #需要进行复制的数据库,可以指定数据库,这里我注释掉不用
binlog-do-db=ds_0
binlog-do-db=ds_1
master容器设置
#进入master容器docker exec -it [主容器id] bash/sh
#启动mysql命令,刚在创建窗口时我们把密码设置为:rootmysql -u root -p
#创建一个用户来同步数据,每个slave使用标准的MySQL用户名和密码连接master。进行复制操作的用户会授予REPLICATION SLAVE 权限。
CREATE USER 'repl'@ '%' IDENTIFIED BY 'repl';
#这里表示创建一个slave同步账号repl,允许访问的IP地址为%,%表示通配符//查看状态,记住File、Position的值,在Slave中将用到
GRANT REPLICATION SLAVE ON *.* to 'repl'@'%' identified by 'repl';
#查看状态
show master status;
slave容器设置
#进入slave容器
docker exec -it [从容器id] bash/sh
#启动mysql命令,刚在创建窗口时我们把密码设置为:root
mysql -u root -p
#连接主mysql服务
change master to master_host='172.30.0.4',master_user='repl',master_password='repl',master_log_file='mysql-bin.000013',master_log_pos=154,master_port=3306;
#启动从库同步
start slave;
#查看状态
show slave status\G;
命令说明:
master_host :Master 的地址,指的是容器的独立 ip, 可以通过 docker inspect f51d143d5383容器名称 | 容器 id 查询容器的 ip
master_port:Master 的端口号,指的是容器的端口号
master_user:用于数据同步的用户
master_password:用于同步的用户的密码
master_log_file:指定 Slave 从哪个日志文件开始复制数据,即上文中提到的 File 字段的值
master_log_pos:从哪个 Position 开始读,即上文中提到的 Position 字段的值
master_connect_retry:如果连接失败,重试的时间间隔,单位是秒,默认是 60 秒
在 Slave 中的 Mysql 终端执行 show slave status \G; 用于查看主从同步状态。
正常情况下,SlaveIORunning 和 SlaveSQLRunning 都是 No,因为我们还没有开启主从复制过程。使用 start slave 开启主从复制过程,然后再次查询主从同步状态 show slave status \G;。
SlaveIORunning 和 SlaveSQLRunning 都是 Yes,说明主从复制已经开启。此时可以测试数据同步是否成功。
常见错误
SlaveIORunning一直是Connecting
使用 start slave 开启主从复制过程后,如果 SlaveIORunning 一直是 Connecting,则说明主从复制一直处于连接状态,这种情况一般是下面几种原因造成的,我们可以根据 Last_IO_Error 提示予以排除。
网络不通
检查 ip, 端口
密码不对
检查是否创建用于同步的用户和用户密码是否正确
pos 不对
检查 Master 的 Position
mysql8特有的密码规则问题引起:
ALTER USER 'slave'@'%' IDENTIFIED WITH mysql_native_password BY '@#$Rfg345634523rft4fa';
将密码规则修改为:mysql_native_password
Slave_SQL_Running: No 错误
stop slave;
set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
start slave;
第一次操作完毕之后,输入命令show slave status\G ,发现还是没变,又操作了一次,就好了
Got fatal error 1236 from master when reading data from binary log
主库中执行:
flush logs;
show master status;
记下File, Position。
从库中执行:
CHANGE MASTER TO MASTER_LOG_FILE='testdbbinlog.000008',MASTER_LOG_POS=107;
slave start;
show slave status \G
主从同步验证
在master主库容器中,创建数据库ds_0,并在此库下创建表user_0,并插入一条记录
此时,进入从库容器中,查看:
参考文献: