复制的简单概述
复制(replication)是Mysql数据库提供的一种高可用性能的解决方案,它解决的问题是让一台服务器的数据与其他服务器保持一致,一台主库的数据可以同步到多台备库上,备库本身也可以被配置成另外一台服务器的主库,主库和备库之间有多种不同的组合方式。
Mysql中的复制分为两种:基于行的复制和基于语句的复制(二者下文介绍),这两种方式都是通过在主库上记录二进制日志(bin log),在备库上使用重放日志(relay log)来实现异步的数据复制。需要注意的是,无论是哪种复制,都是有延迟的,在同一时间点备库上的数据和主库上的数据并不是一致的,一些大的语句可能导致备库产生机几秒、几分钟、甚至几个小时的延迟。
为什么要有复制
因为我们的需要,所以才有了复制的功能,那么复制解决了哪些问题?
1、高可用性和故障切换
复制可以帮助应用程序避免Mysql单点失败,快速的切换系统能够显著缩短宕机的时间。
2、备份
复制是Mysql中备份的一种技术补充,但复制并不是备份,也不能取代备份。
3、Mysql升级测试
Mysql需要升级的时候,使用更高版本的Mysql作为备库。
4、数据分布
Mysql中的复制操作不会对带宽造成很大的压力,所以当网络环境不够稳定的时候,也可以完成复制操作,可以在不同的地理位置来分布数据备份,但是网络延迟高,那复制的延迟也会变高。
5、负载均衡
通过Mysql复制可以将读操作分布到多个服务器上,实现对读密集型应用的优化,并且实现方便。外界客户端可以从各个备份中来读取数据,但是写入从主机上写入,也就是实现了读写分离,分散压力,提高性能。
复制的工作方式
复制工作主要分为3个步骤:
1、在主库上把数据的更改记录到二进制文件(bin log)中。
2、备库将主库上的日志复制到自己的中继日志(relay log)中。
3、备库读取中继日志中的事件,将其重新放到备份数据库中。
工作图如下:
1、第一步就是将主库中提交后的事务记录到bin log 文件中。
2、第二步,备库会启动一个工作线程,称为I/O线程,该线程会和主库建立一个普通的客户端连接,然后在主库上启动一个特殊的二进制转储(binlog dump)线程,这个二进制转储线程会读取主库上二进制文件中的事件给备库中的I/O线程,该二进制存储线程不会对事件进行轮询,如果该线程读取的进度追上了二进制文件中的事件,它就会进入休眠状态,直到主库发送信号量通知其有新的事件产生时才会被唤醒,然后备库中的I/O线程将接收到的事件记录到中继日志中。
3、第三步是备库中的SQL线程从中继日志中读取事件并在备库执行,读入备库自己的二进制文件中从而实现备库数据的更新;当SQL线程追赶上I/O线程时,中继日志通常已经在系统缓存中,所以中继日志的开销很低。
复制方式的分类
Mysql中支持两种复制方式:基于行的语句的复制(逻辑复制)和基于行的复制。
基于语句的复制
在Mysql5.0之前的版本中只支持基于语句的复制,基于语句的复制下,主库会记录那些造成数据更改的SQL语句,当备库读取并重放这些事件时,实际上只是把主库上执行过的SQL再执行一遍。
优点
1、简单,理论上只需要记录和执行这些SQL语句即可。
2、另一个好处是记录在bin log 文件里的事件比较紧凑,所以相对而言,基于语句的复制不会使用太多的带宽,除此之外,该方式占用存储空间少,一条更新好几兆的语句在二进制日志里可能只占几十个字节。
缺点
1、主库和备库中同一条SQL的执行时间可能会不相同,在主库中就是单纯的SQL,但传输到备库中除了SQL外,还会包含一些元数据信息,例如时间戳,并且备库可能存在无法正确复制SQL的现象。
2、更新必须是串行的,另外并不是所有的存储引擎都支持这种复制方式。
基于行的复制
Mysql 5.1开始支持基于行的复制,这种方式也是将实际数据记录到二进制日志当中,只不过在复制的过程中是一行一行来复制。他的优点就是可以正确的复制每一行,效率更高。几乎没有基于行复制无法处理的场景,对于所有的SQL构造、触发器、存储过程等都能够正确执行。在某种情况下,基于行的复制能够帮助更快地找到并解决数据不一致的情况,举个例子:如果是使用基于语句的复制模式,在备库更新一个不存在的记录时不会失败,但是基于行的复制模式下则会报错并停止复制。
这两种方式没有哪一种是完美的,MySQL可以在这两种复制模式间动态的切换,默认情况下都是使用的基于语句的复制方式,但是如果发现语句无法被正确的复制,就切换到行的复制模式。
复制的实现
复制的原则:
1、每个备库必须有一个唯一的服务器ID。
2、一个主库可以有多个备库(或者对应的,一个备库可以有多个兄弟备库)。
3、如果打开了 log_slave_updates 选项,一个备库可以把其主库上的数据变化传播到其他备库。
4、在MySQL 5.7 之前,一个备库实例只能有一个主库。
一主库多备库
除了最简单的两台服务器做主备结构外,一主多从的结构和基本配置差不多,备库之间是没有交互的(从技术上讲这并非正确,如果有重复的服务器ID,它们将陷入竞争,并反复将对方从主库上踢出),它们仅仅是连接到同一个主库上。
当有少量的写和大量的读时,这种配置是非常有用的,主库只负责写操作,可以把读操作分摊到多个备库上,直到备库给主库造成了太大的负担,或者说主备之间传输的带宽达到瓶颈时,可以取消备库上的读操作。
尽管这是非常简单的拓扑结构,但是它非常灵活,能够满足多种需求,下面是它的一些用途:
1、把一台备库服务器作为待用的主库,除了复制没有其他数据传输。
2、将一台备库放到远程数据中心,作为灾难恢复。
3、使用其中一个备库,作为备份、培训、开发或者测试使用服务器。
4、为不同的角色使用不同的备库(例如备库和主库的存储引擎不同,但不建议这么做)。
这种结构流行的原因是它比较简单,例如:可以方便的比较不同备库重放事件在主库二进制日志的位置,换句话说,如果在同一个逻辑点停止所有备库的复制,它们正在读取的是主库上同一个日志文件的相同的物理位置,这种特性只存在于兄弟备库之间,可以减轻管理员的许多工作,例如把备库升级为主库。
实现
1、进入主服务器之后,进入my.cnf文件
#进入my.cnf文件
vi /etc/my.cnf
2、修改配置文件里面的内容,加入如下内容:
# 主服务器的配置
#日志文件的名称
log-bin=master-a-bin
#二进制日志格式,有row、statement和mixed三种类型
binlog-format=ROW
#要求各个服务器的该id必须不一样
server-id=1
#同步数据库的名称(自己创建的)
binlog-do-db=copy
#允许外界可以连接该虚拟机
bind-address = 0.0.0.0
注意:如果mysql是使用docker安装的,需要修改docker容器里面的 my.cnf文件。
进入mysql容器后依次执行命令如下:
#如果没有安装vim 需要依次执行下面两个命令,安装则不用执行
apt-get update
apt-get install vim
#执行下面命令之后,将上面的配置文件内容放进去。
vim /etc/mysql/my.cnf
3、登录mysql
#用户名是root,密码是123456;可以自定义(u是user的意思,p是password的意思)
mysql -uroot -p123456
4、创建自己想要复制的数据库
#创建自己想要进行复制的数据库(copy 是数据库的名字)
create database copy;
#查看该服务器里面有多少个数据库
show databases;
5、使主服务器可以被外界连接,依次执行以下命令。
#mysql 8.0版本之后的 用户信息在 mysql 表里面,所以我们需要进入msyql 表来修改一些系统信息
use mysql;
#用户默认信息都存放在user表里面,所以需要更改user表中root用户的host,如果host 为 localhost表示只允许该服务器连接mysql,
#我们需要将它改为 ‘%’通配符,表示任何服务器都可以连接该服务器的msyql
update user set host='%' where user='root';
#然后刷新权限
flush privileges;
6、修改从服务器的my.cnf配置文件,在配置文件中加入如下配置:
#master -slave copy---slave
#日志文件名称
log-bin=master-a-bin
#二进制日志格式和主服务器一样
binlog-format=ROW
#各个服务器id不能一样
server-id=2
#中继日志执行之后,这些变化是否需要计入自己的bin log。当从服务器需要作为另外
#一个主服务器的时候需要打开
log-slave-updates=true
7、登录从服务器中的mysql之后,创建和主服务器一样的数据库
create database copy;
8、进入主服务器的mysql,查看mysql状态
show master status;
9、重启主、从服务器的mysql,需要使配置文件生效。
10、从服务器进入mysql 然后执行以下命令给从服务器授权(和上图中的主服务内容对应上)
CHANGE MASTER TO MASTER_HOST='192.168.162.128',MASTER_USER='root',MASTER_PASSWORD='123456',MASTER_LOG_FILE='master-a-bin.000001',MASTER_LOG_POS=156;
#解释
MASTER_HOST:主服务器ip地址
MASTER_USER:主服务器root用户
MASTER_PASSWORD:主服务器密码
MASTER_LOG_FILE:主服务器bin文件名
MASTER_LOG_POS:主服务器偏移量
11、刷新权限
flush privileges;
12、启动复制
start slave;
13、查看状态
show slave status \G;
下面是整理常见的错误:
1、如果为connecting表示正在连接主服务器,没有连接上,正确的应该是yes
这时需要主服务器授权,回到第5步。
2、如果 slave IO Running 为 NO,往下找找,查看下面报的错误:
提示server id重复了,需要在my.cnf文件里面进行修改,临时修改可以使用如下方法:
#查看从服务器server id
show variables like 'server_id';
#如果和主服务器一样,则修改server id
set global server_id = 2;
#之后重新启动查看状态
start slave;
show slave status \G;
3、如果slave _SQL_Running 为No:
出现上面错误的原因一般是主库的操作无法复制到从库,比如从库自己先建了一个表,主库也建了一个和从库一样名字的表,从库就会无法同步,产生上面的错误。
也是查看错误之后,依次执行以下语句
stop slave;
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
start slave;
show slave status \G;
问题思考
1、如果先搭建了一台从服务器,这时主库建立了一张新表,然后又搭建了第二台从服务器,那新建的这张表会同步到第二台服务器吗?
答:不会。
2、如果从服务器宕机了一段时间,这期间主服务中的操作还会同步到从服务器吗?
答:会。
3、如果从服务器宕机了一段时间,然后再次启动,需要重新配置连接到主服务器吗?
答:不用,重新启动复制命令(start slave)即可。
4、从服务器可以自己创建表吗?
答:可以,但是不会影响主服务器和其他从服务器。如果内容和主服务器重复,则会报错,SQL 线程就会停止运行。
以上问题是我验证过的,如果错误,欢迎指出。