前言:Mysql内建的复制功能是构建基于Mysql的大规模,高性能应用的基础,这类应用使用所谓的"水平扩展"的架构,我们可以通过为服务器配置一个或者多个备库进行数据同步。复制功能不仅有利于构建高性能的应用,同时也是高可用性,可扩展性,灾难恢复,备份以及数据仓库等工作的基础。本文基于《高性能Mysql》第十章的内容简述复制的原理,同时记录自己搭建Mysql主从的过程。
1.Mysql复制原理简述
复制解决的基本问题是让一台服务器与其他服务器保持同步,一台主库数据可以同步到多台备库,备库本身也可以被配置为另外一台服务器的主库。
Mysql支持两种复制方式:基于行的复制和基于语句的复制。这两种方式都是通过在主库上记录二进制日志,在备库重放日志的方式来实现异步的复制。复制不会增加主库的开销,主要是启用二进制日志带来的开销。
复制解决的问题:
数据分布。可以基于不同地理位置分布数据备份
负载均衡。实现对读的优化,通常可以将写操作几种在主库,用轮询的方式在备库进行读操作,做到读写分离。
备份。复制对于备份来说是一种技术补充,但是也不能完全替代备份
高可用和故障切换。一个良好的故障切换系统能缩短宕机时间
2.复制如何工作
复制有三个步骤:
在主库上把数据更改记录到二进制日志(Binary Log)中(这些记录被称为二进制日志事件)
备库将主库上的日志复制到自己的中继日志(Relay Log)中
备库读取中继日志中的事件,将其重放到备库数据上。
如图:
第一步是在主库上记录二进制日志(需要在mysql配置文件中配置开启)。在每次准备提交事务完成数据更新前,主库将数据更新的时间记录到二进制日志中。Mysql会按照事务提交的顺序而非每条语句的执行顺序来记录二进制日志。在记录二进制日志后,主库会告诉存储引擎可以提交事务了。
下一步,备库将主库的二进制日志复制到本地的中继日志中。首先,备库会启动一个工作线程,称为I/O线程,I/O线程跟主库建立一个普通的客户端连接,然后再主库启动一个特殊的二进制转储(binlog dump)线程,这个二进制转储线程会读取主库上二进制日志中的事件。它不会对事件进行轮询。如果该线程追赶上了主库,它将进入睡眠状态,直到主库发送信号量通知其有新的事件产生时才会被唤醒,备库I/O线程会将接收到的事件记录到中继日志中。
备库的SQL线程执行最后一步,该线程从中继日志中读取事件并在备库执行,从而实现备库的更新。
3.手动实现主从配置
我选择了基于Docker搭建主从复制,这样可以节省机器,一台机器上运行多个Docker容器,并且有独立的Ip,互补冲突,同时能省去繁琐的配置步骤。首先进入自己的机器,我是登录上了阿里云上的一台ECS。拉取Docker镜像:
docker pull mysql:5.7
复制
成功后使用此镜像启动容器,分别启动主从两个容器。
Master(主):
docker run -p 3310:3306 --name mysqlmaster -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
复制
Slave(从):
docker run -p 3311:3306 --name mysqlslave -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
复制
docker ps
可以看到我们启动了两个容器
[root@top ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
646b77f51a04 mysql:5.7 "docker-entrypoint.s…" 2 seconds ago Up 1 second 33060/tcp, 0.0.0.0:3311->3306/tcp mysqlslave
351d72785f0d mysql:5.7 "docker-entrypoint.s…" 17 seconds ago Up 17 seconds 33060/tcp, 0.0.0.0:3310->3306/tcp mysqlmaster
复制
master映射的是3310端口,slave映射的是3311端口,用Navicat可以连接两个端口,对数据库进行操作,这里我通过SSH-Tunnel将服务器对应端口转发到本地,用Navicat直连本地的3310和3311端口:
连接成功后开始配置。
配置Master
进入容器内部
docker exec -it mysqlmaster /bin/bash
复制
cd/etc/mysql
切换到/etc/mysql目录下,然后 vimmy.cnf
对my.cnf进行编辑。此时会报出bash: vi: command not found,需要我们在docker容器内部自行安装vim。使用apt-get install vim命令安装vim
会出现如下问题:
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package vim
复制
执行 apt-getupdate
,然后再次执行 apt-getinstall vim
即可成功安装vim。然后我们就可以使用vim编辑my.cnf,在my.cnf中添加如下配置:
[mysqld]
## 同一局域网内注意要唯一,这里最好不要使用1,因为有些版本不允许id为1,一种通用的办法是使用ip的后8位,要找到规律遵循防止重复。
server-id=10
## 开启二进制日志功能,可以随便取(关键)
log-bin=mysql-bin
复制
配置完成之后,需要重启mysql服务使配置生效。使用 service mysql restart
完成重启。重启mysql服务时会使得docker容器停止,我们还需要 docker start mysqlmaster
启动容器。
下一步在Master数据库创建数据同步用户,授予用户slave REPLICATION SLAVE权限和REPLICATION CLIENT权限,用于在主从库之间同步数据。
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
复制
show master status
可以看到刚刚的配置生效:
配置Slave
首先用同样的方式进入 vimmy.cnf
编辑,
#这里Id必须和master不一样
server-id=11
## 开启二进制日志功能,以备Slave作为其它Slave的Master时使用
log-bin=mysql-bin //为简单起见这里log和master相同
## relay_log配置中继日志
relay_log=mysql-relay-bin //可以不配置使用默认配置
复制
配置完成后同样需要重启服务,并重启容器。下面的操作需要知道server的Ip,所以我们通过以下命令查看docker容器的ip
docker inspect --format='{{.NetworkSettings.IPAddress}}' mysqlmaster
//返回 172.17.0.2
docker inspect --format='{{.NetworkSettings.IPAddress}}' mysqlslave
//返回 172.17.0.3
复制
此时在slave上执行以下命令:
change master to master_host='172.17.0.2',
master_user='slave',
master_password='123456',
master_port=3306,
master_log_file='mysql-bin.000001',
master_log_pos= 0,
master_connect_retry=30;
复制
masterlogpos要设置为0,因为要从master日志的0位置开始读。其实这并不是说Master执行到0,其实刚才在master上看到pos是154,但是并不影响结果,从 pos=0
开始读即可。
查看slave状态,执行:
show slave status
复制
可以看到 Slave_IO_Running=NO
, Slave_SQL_Running=NO
,
接下来执行
start slave //启动主从复制
复制
可以看到 Slave_IO_Running=YES
, Slave_SQL_Running=YES
,
上述两个状态即为yes,说明此时主从复制已经建立完成。
此时我们可以在master上建立一个 testdb
的数据库,然后在slave上执行 show databases
,发现 testdb
已经自动建立。
至此,Mysql主从搭建已经完成。
4.一些补充
上述例子是基于两个数据库都是新建的,且没有数据的前提下进行的主从架构搭建,这并不是典型的案例。如果在生产环境,主库已经运行了一段时间,备库是新买的服务器,还没有数据,还需要其他技术来初始化备库的数据,下面是一些复制的方法:
使用冷备份 即关闭主库,将数据复制到备库,然后再开启主库
使用热备份 使用与MyISAM表
使用mysqldump 如果是Innodb可以使用以下命令
mysqldump--single-transaction--all-databases--master-data-1--host=server1|mysql--host=server2
使用快照或备份
使用备份工具Percona Xtrabackup
这些细节本文就不深究了。
其次本文搭建的主从环境是一主一从,实际情况通常是一主多从,解决的方案是在一主一从的基础上将备库的设置 log_slave_updates
打开,这样从库可以作为另外一台机器的主库,架构图如下:
一主多从的结构也需要遵循以下原则:
一个备库实例只能有一个主库
备库和主库的service-id不同
一个主库可以有多个备库
如果打开了logslaveupdates,一个备库可以把主库的数据变化传播到其他备库。
以上就是我关于Mysql复制这个话题的一些学习记录和实践。
往期文章 : Innodb如何解决页断裂问题