MySQL主从复制
由于数据的大量增加,访问量越来越复杂,有时候需要来部署多个数据库,通过数据库的复制策略,可以将一台mysql数据库服务器中的数据复制到其他的mysql数据库服务器之上,当各台数据库服务器上都包含相同数据的时候,前端应用通过访问mysql集群中任意一台服务器,都能够读取到相同的数据,这样,每台mysql服务器所需要承担的负载就会大大降低,从而提高整个系统的承载能力,达到系统扩展的目的
MySQL支持单向、异步复制,复制过程中一个服务器充当主服务器,另外一个或多个其它服务器充当从服务器。
Mysql的主从复制中主要有三个线程:master(binlog dump thread)、slave(I/O thread 、SQL thread)
master(binlog dump thread)
主要负责Master库中有数据更新时,将更新事件写入到binlog中,并且Master会创建log dump线程通知slave库
slave(I/O thread)
线程用于请求Master库,Master会返回binlog的名称以及当前数据更新的位置、binlog文件位置,并将Master库中的binlog保存在relay log中
slave(SQL thread)
线程检测relay log更新,将更新的内容同步到数据库中,保证主从数据的同步
复制方式
主从复制的几种方式:
同步复制:
所谓的同步复制,意思是master的变化,必须等待slave-1,slave-2,…,slave-n完成后才能返回。这样,显然不可取,也不是MySQL复制的默认设置。比如,在WEB前端页面上,用户增加了条记录,需要等待很长时间。
工作过程
- 当执行提交语句时,事务会被发送到slave,slave开始准备事务的提交
- 每个slave都要准备事务,然后向master发送ok(或abort)消息,表示事务已经准备好(或无法准备该事务)
- master等待所有的slave发送ok(或abort)消息
- 如果master接收到所有slave的ok消息,会向所有slave发送提交消息,告诉slave提交该事务
- 如果master收到来自任何一个slave的abort消息,就会向所有的slave发送abort消息,告知slave去中止事务
- 每个slave等待来自master的ok(或abort)消息
- 如果slave收到提交请求,他们就会提交事务,并向master发送事务已提交的确认
- 如果slave收到取消请求,他们就会撤销所有改变并释放所占用的资源,从而中止事务,并向master发送事务已中止的确认
- master接收到所有来自slave的确认后,才会报告该事务被提交(或中止),然后处理下一个事务
异步复制:
如同AJAX请求一样。master把binlog日志发送给slave,并不会验证slave是否接收完毕
异步复制的性能提升是以牺牲一致性为代价的,当master或slave发生故障时,有可能slave并没有接收到master发送的binlog日志,会造成主从数据不一致
半同步复制:(5.5新增)
master只保证slaves中的一个操作成功,就返回,其他slave不管,半同步复制只与IO线程有直接关系,与SQL线程没有关系,从库接收到二进制日志后就会给主库回复确认信息,并不会管relaylog是否执行完。这个功能,是由google为MySQL引入的,为了解决异步复制的一致性问题
在事务被提交到存储引擎之后但还没有提交给slave之前,如果系统发生崩溃,由于事务是在已被提交的slave后再被确认已提交给客户端的,因此最多只会丢失一个事务
半同步复制的配置
master安装master 插件
install plugin rpl_semi_sync_master soname 'semisync_master.so';
slave安装slave插件
`install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
master启用该插件 在配置文件中配置
1
2
3
4[mysqld]
rpl-semi-sync-master-enabled=1
rpl-semi-sync-master-timeout=200 # 防止半同步复制在没有收到确认的情况下发生堵塞,可以设置一个超时时间,超过该时间将降级为异步复制模式,如果主库再次探测到从库恢复了,会自动回到半同步复制模式,单位毫秒
rpl-semi-sync-master-wait-no-slave=off # 如果一个事务被提交,但是master没有任何slave连接,这时master不可能将事务发送到slave,默认情况下master会在时间限制范围内继续等待slave的连接,并确认该事务已被正确写入到磁盘上,可以使用该选项来关闭这种行为,如果没有slave连接,则恢复到异步复制slave启用该插件 在配置文件中配置
1
2[mysqld]
rpl-semi-sync-slave-enabled=1
半同步相关的变量
1 | -- 查看状态变量 |
rpl_semi_sync_master_clients
展示支持和注册半同步复制的已连接的slave数量rpl_semi_sync_master_status
master的半同步复制状态,1是活动状态,0是非活动状态rpl_semi_sync_slave_status
slave的半同步复制状态,1是活动状态,0是非活动状态rpl_semi_sync_master_yes_tx
显示从服务器确认的成功提交数量rpl_semi_sync_master_no_tx
显示从服务器确认的不成功提交数量
基本原理
MySQL复制是基于主服务器在二进制日志中跟踪所有对数据库的更改。因此,要进行复制,必须在主服务器上启用二进制日志。每个从服务器从主服务器接收主服务器已经记录到日志中的数据。
当一个从服务器连接主服务器时,它通知主服务器最后一次成功更新的位置。从服务器接收那时起发生的任何更新,保存在中继日志(relay log)中,重做中继日志的的更新时间。然后封锁并等待主服务器通知新的更新。从服务器执行备份并不干扰主服务器,灾备份过程中主服务器可以继续处理更新。
主从复制的数据完整性依赖于主库的binlog,只要主库的binlog不丢失,数据就不会丢失
mysqlbinlog可以访问到主库的binlog
过程
1 | -- 查看binlog刷新到磁盘的频率,默认是1 |
- master将改变记录到bin log中,这些记录过程叫做二进制日志事件,binary log events
- 事件写入binlog之后,master的转储线程(dump thread)从binlog中读取事件,将它们发送给slave的IO线程
- slave的io线程接收到事件之后写入到它的中继日志(relay log)
- slave的sql执行线程执行中继日志中的sql,将改变应用到自己的数据库中,MySQL的复制是异步且串行化的
由于复制过程是异步的,因此,master和slave之间的数据有可能存在延迟的现象,此时只能够保证数据最终的一致性
用到的命令
1 | -- 查看复制状态信息,展示连接到master的slave信息,包括通过中继连接到master的slave |
master的状态变量
1 | -- 显示show master status命令执行的次数 |
slave的状态变量
1 | -- show slave status命令执行的次数 |
主从一致性检验工具
checksum、mysqldiff、pt-table-checksum等
主从架构
一主一从、一主多从、双主、级联同步、环形多主
一主一从配置
如果读多写少的情况下也可以配置为一主多从
主MySQL
修改my.cnf,在 [mysqld]模块下面添加以下几行
1 | server-id = 11 //主服务器编号,id要唯一 |
1 | -- 为所有从服务器授权所有数据库 |
1 | -- 删除所有的二进制文件并清空二进制索引文件,执行该命令前要确保当前没有slave连接该master |
从MySQL
修改my.cnf,在 [mysqld]模块下面添加以下几行
1 | server-id = 22 //从服务器编号 |
1 | -- 指定主服务器 master_log_pos是在show master status;时的position |
如果要停止主从复制
1 | stop slave; |
如果要重新配置主从
1 | stop slave; |
双主配置
由于一主一从存在单点问题,如果主挂掉会导致无法写入
双主有两种不同的配置方法
active-active
该配置方法,操作同时写入两个服务器,然后将更改转移到其他master存在的问题:
- 如果同样的信息在两个master上都被更新,这两个更新之间会有冲突,并很可能导致复制停止
- 当两个master不一致时,如果系统发生崩溃,一些交互将会丢失
active-assive
该配置方法,其中一个Master处理写入,称为主动master;另一个服务器称为被动master,只是和主动master保持一致存在的问题
- 由于网络原因,导致主动master无法连接,此时被动master主动提升为主动master,但是随后,原来的主动master又再次连接成功,此时两台服务器都作为主动master,此时的更改在两台master上都被执行,就有可能发生冲突
master1
1 | server-id = 11 //主服务器编号,id要唯一 |
master2
1 | server-id = 12 //主服务器编号,id要唯一 |
两个主机之间需要相互复制
1 | -- 两个mysql服务器都需要执行 |
为了防止两台MySQL之间循环复制,会在MySQL的binlog中记录当前MySQL的server-id,且两台机器的server-id参数不同,MySQL就可以判断出哪个变更是哪一个MySQL Server产生的,从而避免了循环复制的情况
为了可以更好的增加机器,id自己生成,不再使用自增id,否则在配置auto-increment-increment和auto-increment-offset时每次添加机器都要修改
级联复制
有时候在一些应用场景中,会存在读写压力差别比较大,读压力特别大,一个Master可能需要多台Slave才能支撑读的压力,但是一台Master给多台slave复制会消耗较多的资源,很容易造成复制的延时。
此时可以先有几台MySQL从master来进行复制,这几台MySQL称为第一级slave集群,也可以成为中继slave,然后其他slave再从第一级slave集群中进行复制,这些slave称为第二级slave集群
中继slave
中继slave需要binlog来保存所有改变,因为中继slave需要将改变传递给其他slave,但是中继slave又不需要应用这些改变,因为它并不响应任何查询
所以中继slave中的所有表的存储引擎改为BLACKHOLE,该存储引擎是黑洞引擎,写入的任何数据都会消失,专门用于记录binlog做复制的中继存储