前言
前面已经学到了很多知识,大部分也都是偏向于应用方面,在应用实战这条路上,博主一直觉得只有实战才是学习中最快的方式。今天带来主从复制给大家,在刚刚开始动手写的时候,才想到似乎忽略了一些重要的东西,不过还好,既然想到了,就会在本文中体现出来,争取让大家学完之后明白主从复制的原理和怎么去做主从复制。
什么是主从复制
MySQL主从复制是一个异步的复制过程,底层是基于Mysql数据库自带的 二进制日志 功能。就是一台或多台MySQL数据库(slave,即从库)从另一台MySQL数据库(master,即主库)进行日志的复制,然后再解析日志并应用到自身,最终实现 从库 的数据和 主库 的数据保持一致。MySQL主从复制是MySQL数据库自带功能,无需借助第三方工具。
二进制日志(BINLOG)记录了所有的 DDL(数据定义语言)语句和 DML(数据操纵语言)语句,但是不包括数据查询语句。此日志对于灾难时的数据恢复起着极其重要的作用,MySQL的主从复制, 就是通过该binlog实现的。默认MySQL是未开启该日志的。
主从复制分为三步完成:
- MySQL master 将数据变更的SQL语句写入二进制日志( binary log)
- slave将master的binary log拷贝到它的中继日志(relay log),说是拷贝,其实是读取过来,也可以理解成拷贝,内容拷贝
- slave读取中继日志中的事件,将数据变更反映它自己的数据库中
Docker模拟多服务器准备
博主没有办法在真正的两台云端服务器上给大家做演示,所以就在本地给大家模拟一下做法,有虚拟机的使用虚拟机复制出来一个使用,没有虚拟机的可以使用Docker来模拟。
使用Docker模拟时,需要创建两个mysql的容器:
Master(主):
docker run -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql
Slave(从):
docker run -p 3309:3306 --name mysql-slave -e MYSQL_ROOT_PASSWORD=123456 -d mysql
博主没有指定版本,因为博主Image内已经存在一个最新的版本,如果使用的版本略低,可手动指定:
docker run -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:x.x.x
这里需要说明一下端口,由于非生产环境,本地模拟时,端口需要映射,不能全都用3306,所以slave中映射了3309,否则容器启动会因为端口冲突报错。
此时在Docker内,已经有两个运行中的mysql了:
docker ps可以查看运行中的容器:
配置数据库主从
配置Master
docker exec -it 8e46c78ba828 /bin/bash
输入上面的命令,进入master容器内部,8e46c78ba828是容器id,也可以使用容器名mysql进入:
docker exec -it mysql /bin/bash
输入:
cd /etc/mysql
进入mysql的配置文件目录下,对my.cnf进行编辑:
vi my.cnf
正常是会报错的,会提示:
bash: vi: command not found
需要我们在docker内安装vim,这个我们在前面的博客中有提到,为了方便,此处再写一下解决步骤:
输入
apt-get install vim
提示:
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package vim
输入
apt-get update
然后输入
apt-get install vim
等待vim安装完成即可。
注意里面会有一个提示,输入Y。安装过程可能会有点慢,稍安勿躁。
安装完成,此时再输入以下命令:
vi my.cnf
在最下面增加配置:
log-bin=mysql-bin #[必须]启用二进制日志
server-id=100 #[必须]服务器唯一ID(唯一即可)
然后退出保存即可。下面要重启mysql服务,让配置生效:
你可以选择使用命令行
service mysql restart
甚至你还需要重启mysql容器:
docker start mysql
但博主这里偷懒,直接在docker内部重启mysql容器,哈哈!!!
特别注意:你目前所在的文件夹是:root@8e46c78ba828:/etc/mysql
你需要通过两次cd ..回到顶端目录,然后使用:
mysql -uroot -pxxxx
u后面跟账号,p后面跟密码,登录到mysql内:
以上启动sql的命令运行在root@8e46c78ba828:/etc/mysql目录下是不行的,需要你退出docker容器运行才可以,这个是常识哈,我当大家都知道的。
下一步在Master数据库创建数据同步用户,授予slave的访问用户,比如slave,授权 REPLICATION SLAVE权限和REPLICATION CLIENT权限,用于在主从库之间同步数据,分两步完成:
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
到这里,主库的配置就算是完成了,你可以输入:
show master status;
来查看主库的状态:此时主库什么都不要动,这里的File和Position我们后面有用。
配置Salva
接下来我们来配置从库,整体步骤和主库差不多,但是为了让大家不出错,这里还是一步步带着大家操作。
首先新开一个终端窗口:
docker exec -it e2476006aeb4 /bin/bash
输入上面的命令,进入slave容器内部,e2476006aeb4是容器id,也可以使用容器名mysql-slave进入:
docker exec -it mysql-slave /bin/bash
输入:
cd /etc/mysql
进入mysql的配置文件目录下,对my.cnf进行编辑:
vi my.cnf
不出意外的又报错了,还是和主库一样,这是因为两个容器互不相关,所以还需要在此容器安装vim,步骤一样,大家照着上面来。
安装完成,此时再输入以下命令:
vi my.cnf
在最下面增加配置:
log-bin=mysql-bin #[必须]启用二进制日志
server-id=101 #[必须]服务器唯一ID(唯一即可)
然后退出保存即可。下面要重启mysql服务和容器,让配置生效。这里注意,id变了,主库是100,此处是101。
关联主从数据库
进入从数据库中,登陆了从数据库,执行以下命令,设置主库地址及同步位置:
change master to master_host='172.17.0.2',master_user='slave',master_password='123456',master_log_file='mysql-bin.000001',master_log_pos=721;
来解释下这里的数据来源。
ip通过以下命令获得:
docker inspect --format='{{.NetworkSettings.IPAddress}}' 容器id/容器名
master_log_file='mysql-bin.000001',master_log_pos=721;还记得我们通过show master status获得的表格吗?
看看数据对不对的上。
然后执行:
start slave;
为了验证主从关联是否完成,在从库Slave中输入以下命令:
show slave status \G;
\G是因为让显示是一行一行的,否则表格太长,无法直观的看到想要的信息。
查看SlaveIORunning 和 SlaveSQLRunning 都是Yes,说明主从复制已经开启。
此时,SlaveIORunning一直是Connecting,则说明主从复制一直处于连接状态,查看错误:
error connecting to master 'slave@172.17.0.2:3306' - retry-time: 60 retries: 1 message: Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection.
提示我们授权有问题,详情可查看此篇博客:Authentication plugin 'caching_sha2_password' reported error:Authentication..我们采用这篇博客说的第三种办法去解决这个问题,避免使用caching_sha2_password插件,所以我们需要重新创建一个用户:
CREATE USER 'repl'@'%' IDENTIFIED WITH 'mysql_native_password' BY '123456';
前面做的时候没有做远程授权,也会报错,所以这里加上了授权远程访问的权限:
GRANT ALL PRIVILEGES ON *.* TO 'repl'@'%' WITH GRANT OPTION;
我们查看下数据库中用户的列表:
一定要有远程访问的权限才可以,Grant_priv就是,虽然slave用户也授权了远程权限,但是使用了caching_sha2_password,也不可用,所以才新建了repl用户。接着,我们要查看主库的状态,重新获取关键信息:
show master status;
查看主库状态:
发现原来的 721变了,File的文件后缀名也变为02了。这里要注意,一定要用新的,到这里,主库千万不要再去动了,否则会出别的问题。
下面在从库重新关联主从,在这之前,需要先停止slave:
stop slave;
reset slave;
然后执行此命令关联:
change master to master_host='172.17.0.2',master_user='repl',master_password='123456',master_log_file='mysql-bin.000002',master_log_pos=2819;
注意参数改为2819,接着启动slave:
start slave;
查看关联状态:
show slave status \G;
看到两个YES,就说明主从已经配置好了。
关于mysql的授权相关命令,推荐一篇博客给大家:MySql 授权命令grant
测试主从
我们在使用Docker内部IP访问数据库的时候发现无法连接,这是因为这个IP是docker内部id,博主查了很多资料,都没有很好的解决这个问题,但是,也看到了一些说法:
如何访问docker容器ip-Docker-PHP中文网
根据这篇博客,最终得到的结论就是,虽然无法直接访问docker内部ip,但是我们已经通过端口映射到了localhost的端口上,所以,可以把docker内部ip地址换成主机地址,也可以直接用localhost,port使用映射的端口就可以。
还有另一篇博客:
解决docker宿主机不能访问容器的问题_docker宿主机访问不到容器
这篇博客提出在创建容器的时候,容器与宿主机共享同一个网卡,不过博主没有重新创建容器,有兴趣的小伙伴自行尝试。
此时我们通过localhost链接主从数据库,由于主数据库源本来就存在其他的数据库,从库是新的,连接上之后,完全没有问题,俩数据库绝对是完全不一样的,我们使用localhost的做法也是正确的,这位我们测试主从提供了良好的环境。
下面开始测试,在主数据库创建数据库,并创建新表:
create database if not exists master_slave character set utf8;
use master_slave;
CREATE TABLE user (
id bigint(20) primary key auto_increment,
username varchar(32) not null,
password varchar(32) not null,
age int(3) not null ,
phone varchar(32) not null
)
此时用户表已经创建完毕,我们去从库看一下这个表有没有被创建出来:
从库里面已经出现了数据库和用户表,非常棒,主从完美啊,我们在主库用户表添加点数据看看:
insert into user value(null ,'codingfire','123456',20,'13812345678');
查看主库表:
用户信息已经插入,切换到从库查看:
从库也有了,主从复制测试成功。删除修改大家可以自行测试。
注意:细心点,你会发现页面左上角的数据库连接对象是不一样的,所以这里连接docker使用localhost是完全没有问题的。另外,如果docker异常关机等,导致同步的游标出现错乱,需要重新配置日志游标:
stop slave;
change master to master_log_file='mysql-bin.00000x', master_log_pos=xxxx;
start slave;
结语
总的来说,mysql的主从还是没那么复杂的,没有代码操作,全都是配置,在真实的服务器上,配置也基本都是这样,这里学会了,真实的服务器也不在话下。虽然主从复制写完了,但是关于主从的只是只是还没有结束,因为还没在项目中引入主从的使用,下一篇,我们将学习主从在项目中的使用——读写分离。觉得不错,就给博主个赞吧。