暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Mysql的主从搭建原理及实践

来搞笑的Yuan 2019-10-18
257

前言: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镜像:

  1. docker pull mysql:5.7

复制

成功后使用此镜像启动容器,分别启动主从两个容器。

Master(主):

  1. docker run -p 3310:3306 --name mysqlmaster -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7

复制

Slave(从):

  1. docker run -p 3311:3306 --name mysqlslave -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7

复制

docker ps
可以看到我们启动了两个容器

  1. [root@top ~]# docker ps

  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

  3. 646b77f51a04 mysql:5.7 "docker-entrypoint.s…" 2 seconds ago Up 1 second 33060/tcp, 0.0.0.0:3311->3306/tcp mysqlslave

  4. 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

进入容器内部

  1. 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 会出现如下问题:

  1. Reading package lists... Done

  2. Building dependency tree

  3. Reading state information... Done

  4. E: Unable to locate package vim

复制

执行 apt-getupdate
,然后再次执行 apt-getinstall vim
即可成功安装vim。然后我们就可以使用vim编辑my.cnf,在my.cnf中添加如下配置:

  1. [mysqld]

  2. ## 同一局域网内注意要唯一,这里最好不要使用1,因为有些版本不允许id为1,一种通用的办法是使用ip的后8位,要找到规律遵循防止重复。

  3. server-id=10

  4. ## 开启二进制日志功能,可以随便取(关键)

  5. log-bin=mysql-bin

复制

配置完成之后,需要重启mysql服务使配置生效。使用 service mysql restart
完成重启。重启mysql服务时会使得docker容器停止,我们还需要 docker start mysqlmaster
启动容器。

下一步在Master数据库创建数据同步用户,授予用户slave REPLICATION SLAVE权限和REPLICATION CLIENT权限,用于在主从库之间同步数据。

  1. CREATE USER 'slave'@'%' IDENTIFIED BY '123456';


  2. GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';

复制

show master status
可以看到刚刚的配置生效:

配置Slave

首先用同样的方式进入 vimmy.cnf
编辑,

  1. #这里Id必须和master不一样

  2. server-id=11

  3. ## 开启二进制日志功能,以备Slave作为其它Slave的Master时使用

  4. log-bin=mysql-bin //为简单起见这里log和master相同

  5. ## relay_log配置中继日志

  6. relay_log=mysql-relay-bin //可以不配置使用默认配置

复制

配置完成后同样需要重启服务,并重启容器。下面的操作需要知道server的Ip,所以我们通过以下命令查看docker容器的ip

  1. docker inspect --format='{{.NetworkSettings.IPAddress}}' mysqlmaster

  2. //返回 172.17.0.2

  3. docker inspect --format='{{.NetworkSettings.IPAddress}}' mysqlslave

  4. //返回 172.17.0.3

复制

此时在slave上执行以下命令:

  1. change master to master_host='172.17.0.2',

  2. master_user='slave',

  3. master_password='123456',

  4. master_port=3306,

  5. master_log_file='mysql-bin.000001',

  6. master_log_pos= 0,

  7. master_connect_retry=30;

复制

masterlogpos要设置为0,因为要从master日志的0位置开始读。其实这并不是说Master执行到0,其实刚才在master上看到pos是154,但是并不影响结果,从 pos=0
开始读即可。

查看slave状态,执行:

  1. show slave status

复制

可以看到 Slave_IO_Running=NO
, Slave_SQL_Running=NO
, 接下来执行

  1. 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如何解决页断裂问题

文章转载自来搞笑的Yuan,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论