一,复制
复制是指将主数据库的DDL和DML操作通过二进制日志传到复制服务器(也叫从库)上,然后在从库上对这些日志重新执行(也叫重做),从而使得从库和主库的数据保持同步。
MySQL支持一台主库同时向多台从库进行复制,从库同时也可以作为其他服务器的主库,实现链状的复制。
MySQL复制的优点主要包括以下3个方面:
如果主库出现问题,可以快速切换到从库提供服务;
可以在从库上执行查询操作,降低主库的访问压力;
可以在从库上执行备份,以避免备份期间影响主库的服务。
由于MySQL实现的是异步的复制,所以主从库之间存在一定的差距,在从库上进行的查询操作需要考虑到这些数据的差异,一般只要更新不频繁的数据或者对实时性要求不高的数据可以通过从库查询,实时性要求高的数据仍然需要从主数据库获得。
MySQL的复制原理大致如下。
1,首先,MySQL主库在事务提交时会把数据变更作为时间events记录在二进制日志文件binlog上,MySQL主库上的sync_binlog参数控制binlog日志刷新到磁盘。
2,主库推送二进制日志文件binlog中的事件到从库的中继日志relay log,之后从库根据中继日志relay log重做数据变更操作,通过逻辑复制以此来达到主库和从库的数据一致。
MySQL通过3个线程来完成主从库间的数据复制:其中binlog dump线程跑在主库上,I/O线程和SQL线程泡在从库上。当在从库上启动复制(start slave)时,首先创建I/O线程连接主库,主库随后创建binlog dump线程读取数据库事件并发送给I/O线程,I/O线程获取到事件数据后更新到从库的中继日志relay log中去,之后从库上的SQL线程读取中继日志relay log中更新的数据库事件并应用,如图。
可以通过show processlist命令查看数据库相关线程。
二,复制的3种常见架构
复制的3种常见架构有一主多从复制架构,多级复制架构和双主复制/dual master架构。
1,一主多从复制架构
在主库读取请求压力非常大的场景下,可以通过配置一主多从复制架构实现读写分离,把大量对实时性要求不是特别高的读请求通过负载均衡分别到多个从库上,降低主库的读取压力,如果
在主库出现异常宕机的情况下,可以把一个从库切换为主库继续提供服务。
2,多级复制架构
一主多从的架构能够解决大部分读请求压力特别大的场景的需求,考虑到MySQL的复制是主库推送binlog日志到从库,主库的I/O压力和网络压力会随着从库的增加而增长(每个从库都会在主库上有一个独立的binlog dump线程来发送事件),而多级复制架构解决了一主多从场景下,主库额外的I/O和网络压力。MySQL的多级复制架构如图:
对比一主多从的架构图,多级复制仅仅是在主库master1复制到从库slave1、slave2、slave3的中间增加一个二级主库master2,这样,主库master1只需要给一个从库master2推送binlog日志即可,减轻主库master1推送的压力。二级主库的master2再推送binlog日志给从库slave1、slave2、slave3.
多级复制解决了一主多从场景下,主库的I/O负载和网络压力,当然也有缺点:MySQL的复制是异步复制,多级复制场景下主库的数据是经历多次复制才到达从库slave1、slave2、slave3的,期间的延时比一主多从复制场景下只经历一次复制的要大。
可以通过在二级主库master2上选择表引擎为BLACKHOLE来降低多级复制的延时。BLACKHOLE引擎是一个黑洞引擎,写入BLACKHOLE表的数据并不会写回到磁盘上,BLACKHOLE表永远都是一个空表,insert、update、delete操作仅仅在binlog中记录事件。
BLACKHOLE引擎非常适合二级主库master2的场景:master2并不承担读写请求,仅仅负责将binlog日志尽快传送给从库。
3,双主复制/dual master架构
双主复制/dual master架构特别适合用于DBA做维护等需要主从切换的场景,通过双主/dual master架构避免了重复搭建从库的麻烦,双主的架构如图:
主库master1和master2互为主从,所有web client客户端的写请求都访问从库master1,而读请求可以选择访问主库master1或master2.加入,DBA需要做日常维护操作,为了避免影响服务:
首先,在master1库上停止slave线程(STOP SLAVE),避免后续对master2库的维护操作被实时复制到master1库上对服务造成影响;
其次,在master2库上停止slave线程(STOP SLAVE),开始日常维护操作,例如创建索引等;
然后,在master2库上完成维护操作之后,打开master2库上的slave线程(START SLAVE),让master2库的数据和master1库同步,同步完成后,把应用的读写请求切换到master2库上;
最后,确认master1库上无应用访问后,打开master1库的slave线程(START SLAVE)即可。
通过双主复制/dual master架构能够大大减轻一主多从架构下对主库进行维护带来的额外搭建从库的工作。
当然双主复制还能和主从复制联合起来使用:在master2库下配置从库slave1、slave2等,这样既可通过从库slave1等来分担读取压力,同时在DBA做维护的同时,避免了重建从库的额外工作。MySQL的双主多级复制机构如图。
由于MySQL的binlog中会记录事件初始发送的server id。MySQL库只应用和自己server id不同的binlog日志,MySQL通过判断binlog事件中的不欧server id即可判断当前库是否是事件发生的初始server,所以双主复制加上级联复制(打开了log_slave_updates)也不会出现循环复制。
三,复制搭建过程
架构中的每一个MySQL实例的server id要保证唯一。
1,异步复制
MySQL的主从复制至少需要两个MySQL服务,这些MySQL服务可以分别在不同的服务器上,也可以在一台服务器上启动多个服务。
2,半同步复制
在MySQL5.5之前,MySQL的复制是异步操作,主库和从库的数据之间存在一定的延迟,这样存在一个隐患:当在主库上写入一个事务并提交成功,而从库尚未得到主库推送的binlog日志时,主库宕机了,例如主库可能因为磁盘损坏、内存故障等造成主库上该事务binlog丢失,此时从库就可能损失这个事务,从而造成主从不一致。
MySQL5.5引入了半同步复制机制。在MySQL5.5之前的异步复制时,主库执行完commit提交操作后,在主库写入binlog日志后即可成功返回客户端,无需等待binlog日志传送给从库。如图。
而半同步复制时,为了保证主库上的每一个binlog事务都能够被可靠的复制到从库上,主库在每次事务成功提交时,并不及时反馈给前端应用用户,而是等待其中一个从库也接受到binlog事务并成功写入中继日志后,主库才返回commit操作成功给客户端。半同步复制保证了事务成功提交后,至少有两份日志记录,一份在主库的binlog日志上,另一份在至少一个从库的中继日志relay log上,从而更进一步保证了数据的完整性。
半同步复制的大致流程如图。
半同步复制操作下,假如在上图的步骤1,2,3中的任何一个步骤中主库宕机,则事务并未提交成功,从库上也没有收到事务对应的binlog日志,所以主从数据是一致的;假如在步骤4传送binlog日志到从库时,从库宕机或者网络故障,导致binlog并没有及时地传送到从库上,此时主库上的事务会等到一段时间(时间长短由参赛rpl_semi_sync_master_timeout设置的毫秒数决定),如果binlog在这段时间内都无法成功推送到从库上,在MySQL自动调整复制为异步模式,事务正常返回提交结果给客户端。
半同步复制很大程度上取决于主从库之间的网络情况,往返时延RTT越小决定了从库的实时性越好。即,主从库之间网络越快,从库越实时。
往返时延RTT(Round-trip Time)在计算机网络中是一个重要的性能指标,它表示从发送端发送数据开始到发送端接收到接收端的确认,总共经理的时长。
四,日常管理维护
1,多主复制时的自增长变量冲突问题
在大多数情况下,一班只使用单主复制(一台主库对一台或者)。但是在某些情况下,可能需要使用多主复制(多台主库对一台从库)。这时,如果主库的表采用自动增长变量,那么复制到从库的同一张表后可能会引起主键冲突,因为系统参数auto_increment_increment和auto_increment_offset的默认值为1,这样多台主库的自增变量列迟早会发生冲突。在单主复制时,可以采用默认设置,不会有主键冲突发生。但是使用多主复制时,就需要定制auto_increment_increment和auto_increment_offset的设置,保证多主复制到从数据库不会有重复冲突。比如,两个master的情况可以按照以下设置。
master1:auto_increment_increment=2,auto_increment_offset=1;(1,3,5,7…列)。
master2:auto_increment_increment=2,auto_increment_offset=0;(0,2,4,6…列)。
五,参考资料
《深入浅出MySQL 数据库开发、优化与管理维护》