mysql主从复制的原理

什么叫MySQL主从复制
MySQL主从复制是其最重要的功能之一。主从复制是指一台服务器充当主数据库服务器,另一台或多台服务器充当从数据库服务器,主服务器中的数据自动复制到从服务器之中。对于多级复制,数据库服务器即可充当主机,也可充当从机。MySQL主从复制的基础是主服务器对数据库修改记录二进制日志,从服务器通过主服务器的二进制日志自动执行更新。
MySQL主从复制类型
1、基于语句的复制:主服务器上面执行的语句在从服务器上面再执行一遍,在MySQL-3.23版本以后支持。
存在的问题:时间上可能不完全同步造成偏差,执行语句的用户也可能是不同一个用户。
2、基于行的复制:把主服务器上面改编后的内容直接复制过去,而不关心到底改变该内容是由哪条语句引发的,在MySQL-5.0版本以后引入。
存在的问题:比如一个工资表中有一万个用户,我们把每个用户的工资+1000,那么基于行的复制则要复制一万行的内容,由此造成的开销比较大,而基于语句的复制仅仅一条语句就可以了。
3、混合类型的复制:MySQL默认使用基于语句的复制,当基于语句的复制会引发问题的时候就会使用基于行的复制,MySQL会自动进行选择。
在MySQL主从复制架构中,读操作可以在所有的服务器上面进行,而写操作只能在主服务器上面进行。主从复制架构虽然给读操作提供了扩展,可如果写操作也比较多的话(多台从服务器还要从主服务器上面同步数据),单主模型的复制中主服务器势必会成为性能瓶颈。
三 MySQL主从复制工作原理
如下图所示:
mysql主从复制的原理
MySQL主从复制原理及配置实现
主服务器上面的任何修改都会保存在二进制日志Binary log里面,从服务器上面启动一个I/O thread(实际上就是一个主服务器的客户端进程),连接到主服务器上面请求读取二进制日志,然后把读取到的二进制日志写到本地的一个Realy log里面。从服务器上面开启一个SQL thread定时检查Realy log,如果发现有更改立即把更改的内容在本机上面执行一遍。
如果一主多从的话,这时主库既要负责写又要负责为几个从库提供二进制日志。此时可以稍做调整,将二进制日志只给某一从,这一从再开启二进制日志并将自己的二进制日志再发给其它从。或者是干脆这个从不记录只负责将二进制日志转发给其它从,这样架构起来性能可能要好得多,而且数据之间的延时应该也稍微要好一些。工作原理图如下:
mysql主从复制的原理
MySQL主从复制原理及配置实现
实际上在老版本的MySQL主从复制中Slave端并不是两个进程完成的,而是由一个进程完成。但是后来发现这样做存在较大的风险和性能问题,主要如下:
首先,一个进程会使复制bin-log日志和解析日志并在自身执行的过程成为一个串行的过程,性能受到了一定的限制,异步复制的延迟也会比较长。
另外,Slave端从Master端获取bin-log过来之后,需要接着解析日志内容,然后在自身执行。在这个过程中,Master端可能又产生了大量变化并新增了大量的日志。如果在这个阶段Master端的存储出现了无法修复的错误,那么在这个阶段所产生的所有变更都将永远无法找回。如果在Slave端的压力比较大的时候,这个过程的时间可能会比较长。
为了提高复制的性能并解决存在的风险,后面版本的MySQL将Slave端的复制动作交由两个进程来完成。提出这个改进方案的人是Yahoo!的一位工程师“Jeremy Zawodny”。这样既解决了性能问题,又缩短了异步的延时时间,同时也减少了可能存在的数据丢失量。
当然,即使是换成了现在这样两个线程处理以后,同样也还是存在slave数据延时以及数据丢失的可能性的,毕竟这个复制是异步的。只要数据的更改不是在一个事物中,这些问题都是会存在的。如果要完全避免这些问题,就只能用MySQL的cluster来解决了。不过MySQL的cluster是内存数据库的解决方案,需要将所有数据都load到内存中,这样就对内存的要求就非常大了,对于一般的应用来说可实施性不是太大。
还有一点要提的是MySQL的复制过滤(Replication Filters),复制过滤可以让你只复制服务器中的一部分数据。有两种复制过滤:在Master上过滤二进制日志中的事件;在Slave上过滤中继日志中的事件。如下:
mysql主从复制的原理
配置Master的my.cnf文件(关键性的配置)/etc/my.cnf
log-bin=mysql-bin
server-id = 1
binlog-do-db=icinga
binlog-do-db=DB2 //如果备份多个数据库,重复设置这个选项即可
binlog-do-db=DB3 //需要同步的数据库,如果没有本行,即表示同步所有的数据库
binlog-ignore-db=mysql //被忽略的数据库
配置Slave的my.cnf文件(关键性的配置)/etc/my.cnf
log-bin=mysql-bin
server-id=2
master-host=10.1.68.110
master-user=backup
master-password=1234qwer
master-port=3306
replicate-do-db=icinga
replicate-do-db=DB2
replicate-do-db=DB3 //需要同步的数据库,如果没有本行,即表示同步所有的数据库
replicate-ignore-db=mysql //被忽略的数据库
网友说replicate-do-db的使用中可能会出些问题(http://blog.knowsky.com/196961.htm),自己没有亲自去测试。猜想binlog-do-db参数用于主服务器中,通过过滤Binary Log来过滤掉配置文件中不允许复制的数据库,也就是不向Binary Log中写入不允许复制数据的操作日志;而replicate-do-db用于从服务器中,通过过滤Relay Log来过滤掉不允许复制的数据库或表,也就是执行Relay Log中的动作时不执行那些不被允许的修改动作。这样的话,多个从数据库服务器的情况:有的从服务器既从主服务器中复制数据,又做为主服务器向另外的从服务器复制数据,那它的配置文件中应该可以同时存在binlog-do-db、replicate-do-db这两个参数才对。一切都是自己的预测,关于binlog-do-db、replicate-do-db的具体使用方法还得在实际开发中一点点摸索才可以。
网上有说,复制时忽略某些数据库或者表的操作最好不要在主服务器上面进行,因为主服务器忽略之后就不会再往二进制文件中写了,但是在从服务器上面虽然忽略了某些数据库但是主服务器上面的这些操作信息依然会被复制到从服务器上面的relay log里面,只是不会在从服务器上面执行而已。我想这个意思应该是建议在从服务器中设置replicate-do-db,而不要在主服务器上设置binlog-do-db。
另外,不管是黑名单(binlog-ignore-db、replicate-ignore-db)还是白名单(binlog-do-db、replicate-do-db)只写一个就行了,如果同时使用那么只有白名单生效。