1. 基本概念
MySQL主从复制的主要效果简单来说是将两个单独的数据库服务器关联起来,对于主机(Master)以及从机(Slave),从机的数据会伴随着主机数据的变化而同步
2. 主从复制作用
可以解决单个MySQL数据库的以下问题:
- 单点故障服务不可用
- 无法处理大量的并发数据请求
- 数据丢失
对应解决方案:
- 如果主节点出现故障,就直接将服务切到从节点,来保证服务立马可用。
- 如果并发请求特别大的时候,可进行读写分离操作,让主库负责写,从库负责读。
- 如果主库数据丢失,但从库还保存一份,减少数据丢失的风险。
3. 基本原理
3.1 主从复制的三大步骤
- 主机master的更新操作记录到二进制日志(binary log),这个记录的过程为二进制日志事件,binary log events;
- 从机将master的二进制日志拷贝到从机的中继日志(relay log)
从服务器I/O线程将主服务器的二进制日志读取过来写到从服务器本地文件即中继日志文件,然后SQL线程会读取relay-log日志的内容并应用到从服务器,从而使从服务器和主服务器的数据保持一致! - SQL线程实时监控 relay-log日志内容是否有更新,当监控到更新时执行中继日志中的事件,将改变应用到自己的数据库中。 主从复制是异步的且串行化的,而且重启后从接入点开始复制。
3.2 MySQL主从复制的同步方式
(1) 异步复制
MySQL主从同步默认是异步复制的
以上三步中,只有第一步是同步的(即Master写入二进制日志文件后即可成功返回客户端,无需等待binlog响应)
所谓异步复制,就是binlog传递给Slave的过程中,Master不关心Slave有没有将数据写入成功
缺点:
- 如果主从机之间有网络延迟,就会造成短暂的数据不一致的现象。
- 如果主机出现故障,而数据还没有复制过去,则会造成数据丢失
优点: 效率较其他方式最高
(2) 同步复制
即:主机将binlog发送给从机后,Master会触发一个等待,等待所有的Slave节点(如果有多个Slave)返回数据复制成功的信息给Master
优点: 这种方式最安全
缺点: 效率也是最差的
(3) 半同步复制
Master主机将事件发送给Slave主机后会触发一个等待,直到其中一个Slave节点(如果有多个Slave)返回数据复制成功的信息给Master
优点: 在主机确认开销损耗性能以及数据的一致性上采取中庸的策略
半同步复制除了不需要等待所有Slave主机确认事件的接收外,
半同步数据复制并不要求那些事件完全地执行,
因此,仍有可能看到在Slave主机上数据复制延迟的发生,如果因为网络延迟等原因造成Slave迟迟没有返回复制成功的信息,超过了Master设置的超时时长,半同步复制就降级为异步复制方式,而后继续数据复制。
3.3 复制的最大问题:延时
Mysql默认采用的异步操作,因为它的效率明显是最高的。
但是,主机同步写入binlog + 从机异步拷贝日志 + 从机同步执行SQL的过程,从机的数据一定会比主机慢一下,这就是主从复制的延时问题
3.3.1 影响延时的因素:
1)主机如果执行一个很大的事务,那么就会对主从延迟产生较大的影响
2)网络延迟,日志较大,slave数量过多
3)主机上多线程写入,从节点只有单线程同步
4)机器性能问题,从机性能不行
5)锁冲突问题也可能导致从机的SQL线程执行慢
3.3.2 优化主从复制延时
完全解决的方法只有采取同步复制策略,但是显而易见这种方式是对性能影响最大的,除非你不在乎性能,故,在异步复制时可以采取以下几种方式改善延时
1)大事务:将大事务分为小事务,分批更新数据
2)减少Slave的数量,不要超过5个,减少单次事务的大小
3)MySQL 5.7之后,可以使用多线程复制,使用MGR复制架构
4)在磁盘、raid卡、调度策略有问题的情况下可能会出现单个IO延迟很高的情况,可用iostat命令查看DB数据盘的IO情况,再进一步判断
5)针对锁问题可以通过抓取processlist以及查看information_schema下面和锁以及事务相关的表来查看
既然主从机之间的物理延时无法避免,则可以考虑通过缓存等方式降低新修改的数据被立即读取的概率
3.4 复制的基本原则
- 每个slave只能有一个master
- 每个slave只能有一个唯一的服务器ID
- 每个master可以有多个slave
3.5 配置一主一从的简单主从复制
3.5.1 前置条件
配置两个MySQL服务器分别作为主机以及从机,且两机的MySQL版本一致
3.5.2 配置主机
编辑主机的MySQL配置文件:vim /etc/my.cnf
,增加以下配置:
[mysqld]
#主服务器唯一ID
server-id=1
#启动二进制日志
log-bin=mysql-bin
#设置不要复制的数据库(可设置多个)
binlog-ignore-db=mysql
binlog-ignore-db=infomation_schema
#设置需要复制的数据库
binlog-do-db=mytestdb #次数mytestdb是自己需要复制的,自己指定
#设置binlog格式
binlog_format=STATEMENT
logbin日志的三种格式
1. STATEMENT:每一条会修改数据的sql都会记录在binlog中。(DML语言)
优点:不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能。(相比row能节约多少性能与日志量,这个取决于应用的SQL情况,正常同一条记录修改或者插入row格式所产生的日志量还小于Statement产生的日志量,但是考虑到如果带条件的update操作,以及整表删除,alter表等操作,ROW格式会产生大量日志,因此在考虑是否使用ROW格式日志时应该跟据应用的实际情况,其所产生的日志量会增加多少,以及带来的IO性能问题。)
缺点:由于记录的只是执行语句,为了这些语句能在slave上正确运行,因此还必须记录每条语句在执行的时候的一些相关信息,以保证所有语句能在slave得到和在master端执行时候相同的结果。另外mysql 的复制,像一些特定函数功能,slave可与master上要保持一致会有很多相关问题(如sleep()函数, last_insert_id(),以及user-defined functions(udf)会出现问题).
2. ROW:不记录sql语句上下文相关信息,仅保存哪条记录被修改。
优点: binlog中可以不记录执行的sql语句的上下文相关的信息,仅需要记录那一条记录被修改成什么了。所以rowlevel的日志内容会非常清楚的记录下每一行数据修改的细节。而且不会出现某些特定情况下的存储过程,或function,以及trigger的调用和触发无法被正确复制的问题
缺点:所有的执行的语句当记录到日志中的时候,都将以每行记录的修改来记录,这样可能会产生大量的日志内容,比如一条update语句,修改多条记录,则binlog中每一条修改都会有记录,这样造成binlog日志量会很大,特别是当执行alter table之类的语句的时候,由于表结构修改,每条记录都发生改变,那么该表每一条记录都会记录到日志中。
3. Mixedlevel: 是以上两种level的混合使用
一般的语句修改使用statment格式保存binlog,如一些函数,statement无法完成主从复制的操作,则采用row格式保存binlog,MySQL会根据执行的每一条具体的sql语句来区分对待记录的日志形式,也就是在Statement和Row之间选择一种.新版本的MySQL中队row level模式也被做了优化,并不是所有的修改都会以row level来记录,像遇到表结构变更的时候就会以statement模式来记录。至于update或者delete等修改数据的语句,还是会记录所有行的变更。
注:
可以配置主机不需要复制的数据库,一般指定系统库,系统库无需同步
先不要创建指定复制的数据库(这里是mytestdb)。主从搭建好再创建
3.5.3 配置从机
修改配置文件:vim /etc/my.cnf
主从所有配置项都配置在[mysqld]节点下,且都是小写字母
[mysqld]
#从机服务器唯一ID
server-id=2
#启动中继日志
relay-log=mysql-relay
3.5.4 主从机重启配置生效
systemctl restart mysqld
3.5.5 主从机都关闭防火墙
systemctl stop firewalld
3.5.6 在主机上建立帐户并授权slave
#在主机MySQL里执行授权命令
GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%' IDENTIFIED BY '123456';
flush privileges;
#查询master的状态
show master status;
记录下File和Position的值,执行完此步骤后不要再操作主服务器MySQL,防止主服务器状态值变化
3.5.7 在从机上配置需要复制的主机
CHANGE MASTER TO MASTER_HOST='主机的IP地址',
MASTER_USER='slave',
MASTER_PASSWORD='123456',
MASTER_LOG_FILE='mysql-bin.具体数字',MASTER_LOG_POS=具体值;
注意:各个参数都要对应上,主机的IP地址、主机创建的从机账户的账号密码、主机的file名、主机的Position具体地址
例如在作者这里:
3.5.8 在从机上启动主从复制
start slave
查看主从复制的状态: show slave statuys \G
下面两个参数都是Yes,则说明主从配置成功!(代表从机的IO线程跟SQL线程都开启成功)
- Slave_IO_Running: Yes
- Slave_SQL_Running: Yes
如果出现:Slave_IO_Running:No
则可能的解决办法是:
1)停止stop slave; 再启动start slave;看是否能正常运行
2)两个服务器的防火墙是否关闭,是否互相能ping通
3)配置文件是否正确、是否重启了服务器
4)连接主机的语句是否正确
5) 可能是uuid 一致(master,slave uuid) vim /var/lib/mysql/auto.cnf 下更改uuid,重启服务
3.5.9 测试
主机新建库、新建表、插入记录
主机执行新建库、新建表插入数据
create databases mytestdb; # 跟主机配置文件配置的一致
create table zengtbl(id INT,name VARCHAR(16));
insert into zengtbl values(1, 'zeng');
insert into zengtbl values(2, "chuiyu");
检查从机数据可以看出从机数据同步完成,主从复制成功
3.5.10 如果需要停止主从复制,重新配置主从
stop slave
: 在从机上执行,停止主从复制(即停止I/O线程与SQL线程的操作)
reset slave
: 在从机上执行,用户删除slave数据库的relaylog日志文件,并且重新启动新的relaylog文件
reset master
: 在主机上执行,删除所有的binglog日志文件,并将日志索引文件清空,重新开始所有新的日志文件。
以上!