http://www.cnblogs.com/magicsoar/p/7241441.html
一、复制的意义
mysql的复制功能是构建基于MySql大规模,高性能应用的基础,我们可以通过为服务器配置一个或多个备库来进行数据同步;复制功能不仅有利于构建高性能的应用,同时也是高可用性,可扩展行,灾难恢复,备份以及数据仓库等工作的基础
二、复制的方式
Mysql支持3种方式:基于语句的复制、基于行的复制、混合复制。对应的binlog的格式也有三种:STATEMENT,ROW,MIXED
(1)基于语句的复制(SBR)
每一条会修改数据的sql语句会记录到binlog中。优点是不需要记录每一条sql语句和每一行的数据变化,减少了binlog日志量,节约IO,提高性能。缺点是在某些情况下会导致master-slave中的数据不一致(如RAND(),UUID(),存储过程,触发器等)
(2)基于行的复制(RBR)
不记录每条sql语句的上下文信息,转而需记录哪条数据被修改了,修改成什么样了。并且不会出现某些特定情况下的存储过程、触发器等在基于语句复制的模式下导致无法被正确复制的问题。缺点是会产生大量的日志,尤其是alter table的时候会让日志暴涨,无法准确的判断执行了那些sql,此外在备库上改表的schema时会出现复制失败,比如没有在最后加列或删除列
(3)混合复制(MRB)
以上两种模式的混合使用,MySQL会根据执行的SQL语句选择日志保存方式,一般的复制使用STATEMENT模式保存binlog,对于STATEMENT模式无法复制的操作使用ROW模式保存binlog。
三、与复制相关的文件
mysql-bin.index:在服务器上开启二进制日志的同时会生成一个和二进制日志同名的但以.index作为后缀的文件,该文件用于记录磁盘上的二进制日志文件,这里的“index”并不是指表的索引,而是说这个文件的每一行包含了一个二进制的文件名,Mysql依赖于这个文件,除非在这个文件里有记录否则mysql识别不了二进制文件
mysql-relay-bin-index:中继日志的索引文件和mysql-bin.index的作用类似
master.info:这个文件用于保存备库链接到主库所需要的信息,格式为存文本,不同的mysql版本,其记录的信息也可能不同;此文件不能删除,否则备库在重启后无法连接到主库。此外这个文件以文本的形式记录了复制用户的密码,所以要注意对此文件的权限控制
relay-log.info:这个文件包含了当前备库负责的二进制日志和中继日志坐标(例如,备库复制在主库复制的位置),同样也不用删除这个文件,否则备库在重启后将无法获知从哪个位置开始复制,可能导致重放已经执行的语句
四、复制的原理
1、主库把数据更改记录在二进制日志中(Binary Log)中(这些记录被称为二进制日志事件)
2、备库启动一个工作进程,称为I/O线程,通过I/O线程向主库建立一个普通的客户端连接,备库还会启动一个SQL线程
3、在主库上启动一个特殊的二进制转储(binlog dump)线程(该线程没有对应的SQL命令)
4、主库上的二进制转储线程会读取主库上的二进制日志中的事件通过socket连接发送给从库,备库上的I/O线程会将接收到的事件记录到中继日志中;主库上的二进制转储线程不会对事件进行轮询,如果该进程追赶上了主库,它将进入睡眠状态,直到主库发送信号量通知其有新的事件产生时才会被唤醒
5、备库的SQL线程执行最后一步,该线程从中继日志中读取事件并在备库中执行,从而实现备库数据的更新。当SQL线程追赶上I/O线程时,中继日志通常已经在系统缓存中,所以中继日志的开销很低。SQL线程执行的事件也可以通过配置选项来决定是否写入备库的二进制日志中
五、复制的场景
1、同步复制场景
MySQL Cluster(NDB)采用同步复制,保证集群内数据的强一致性。
其基于shared-nothing架构的内存存储引擎,应用场景有限,业务很少采用。
2、异步复制场景
数据写入主库即返回,从库通过IO线程拉取日志,再通过SQL线程进行异步回放。
优点:写入主库即可,无数据复制代价
缺点:业务数据读取不一致;主库crash时,从库数据和主库不一致
应用场景:对数据读取一致性要求不高的业务
3、半同步复制场景
1) 半同步
MySQL 5.5引入了半同步复制(semisync),保证至少有一个slave与master一致。
http://dev.mysql.com/doc/refman/5.6/en/replication-semisync.html
master把数据写入后,将binlog发给slave,半同步复制不要求slave执行,slave收到日志后就发送ack即可,master收到第一个ack后,事务才算结束。
但这种方式可能会造成主从数据不一致:当master innodb commit执行成功,再把binlog同步给slave之前crash,就会造成数据不一致。
2) 分组半同步
采用半同步复制,同机房的从库大概率首先返回ack,这样跨机房容灾成为空谈。于是发展出了分组半同步(semisync + group slave),将不同机房划分为不同的group,每个机房(group)至少有一个从库返回ack,事务才算完成。
优点:半同步和分组半同步最大限度的保证了数据一致性
缺点:
引入同步(等待ack)造成的性能问题
单机房故障会hang住事务,需要退化为异步
数据仍然存在不一致可能
主库在commit和binlog同步之间crash
半同步在超时后会退化为异步(默认10000ms)
3) 无损半同步
由于MySQL 5.5,5.6版本的半同步存在数据不一致问题(先commit后同步),MySQL 5.7.2引入了无损(loessness)半同步,即数据写完slave的relay log后再commit。
https://dev.mysql.com/doc/refman/5.7/en/replication-semisync.html
http://my-replication-life.blogspot.com/2013/09/loss-less-semi-synchronous-replication.html
六、并行复制的方式
1、基于库级别的并行复制
mysql5.6版本
io_thread:根据binlog dump协议从主库拉取binlog, 并将binlog转存到本地的relaylog;
Coordinator_thread:负责读取relay log,将读取的binlog event以事务为单位分发到各个worker thread进行执行;在必要时自己执行binlog event
worker_thread(sql_thread):执行分配到的binlog event,各个线程之间互不影响
多线程原理:
sql_thread的分发是依据当前事务锁操作的数据库名称来进行分发,如果事务是跨分片的,需要等待已分配的改数据库的事务全部执行完毕,才会继续分发
2、基于GroupCommit的并行复制
mysql5.7版本,并行复制的实现添加了另外一种并行的方式,即主库在orderd_commit中的第二阶段的时候,将同一批commit的binlog打上一个相同的seqno标签,同一时间戳的事务在备库是可以同时执行的,因此简化了并行复制的逻辑,并打破了mysql5.6版本相同Db不能并行复制的限制。备库在执行时,具有同一seqno的事务在备库可以并发的执行,互补干扰,也不需要绑定信息,后一批seqno的事务需要等待前一批seqno的事务执行完后才可以执行
优点:对SRB和RBR都支持
缺点:事务越大,DML操作越多,主库上能同时提交的几率越小,从库上回复的并行度也就越小
业务正常压力模式下,主库同时提交的事务并不多,历史备份或者从库schema change后在追若干前的数据所需要的时间无法显著的缩短
3、基于表级别的并行复制
将原有mysql5.6的基于Db基本的分发改成db_name+table_name,不同db_name+table_name的可以分发给不同的worker_thread进行执行
4、基于行级别的并行复制
基于Mysql Row格式的binlog记录了每一行的所有字段信息,因此可以在从中取出每一行的primary key或者unique key,通过db_name+table_name+primary_key来进行冲突检查,对于不冲突的事务可以并行执行,达到行级别的并行复制缺点:只支持RBR
七、其他知识点
1、server id
server_id定义在my.cnf中 server_id = xxx,必须明确指定一个唯一的服务器ID,默认的服务器ID通常为1(这和版本相关,一些mysql版本根本不允许使用这个值)。使用默认值可能会导致和其他服务器的ID冲突,因此要保证它是唯一且不变的
Mysql在复制过程中为了防止环形无限复制,当SQL线程读取中继日志的时候,会丢去事件中记录的服务器ID和该服务器本身ID相同的事件,从而打破复制过程中的无限循环。在某些复制拓扑结构下打破无限循环非常重要,例如主-主复制结构
2、redo log 和 bin log
与oracle 不同,mysql 的主库与备库的同步是通过 binlog 实现的,而redo日志只做为mysql 实例的crash recovery使用。
mysql在4.x 的时候放弃redo 的同步策略而引入 binlog的同步,一个重要原因是为了兼容其它非事务存储引擎,否则主备同步是没有办法进行的。
redo 日志同步属于物理同步方法,简单直接,将修改的物理部分传送到备库执行,主备共用一致的 LSN,只要保证 LSN 相同即可,同一时刻,只能主库或备库一方接受写请求; binlog的同步方法属于逻辑复制,分为statement 或 row 模式,其中statement记录的是SQL语句,Row 模式记录的是修改之前的记录与修改之后的记录,即前镜像与后镜像;备库通过binlog dump 协议拉取binlog,然后在备库执行。如果拉取的binlog是SQL语句,备库会走和主库相同的逻辑,如果是row 格式,则会调用存储引擎来执行相应的修改。