概述
MySQL整体来看,其实就有两块:一块是Server层,它主要做的是MySQL功能层面的事情;还有一块是引擎层,负责存储相关的具体事宜。InnoDB引擎特有的日志是redo log,而Server层的日志称为binlog。binlog记录了对MySQL数据库执行更改的所有操作,binlog文件写到一定大小后会切换到下一个(但一个事务的操作肯定在一个文件中,即大事务引发大文件),其大体作用:
- 恢复:某些数据的恢复需要二进制日志。
- 复制(replication):通过复制和执行二进制日志使一台远程的MySQL数据库(一般为slave或standby)与一台MySQL数据库(一般为master或primary)进行同步。(阿里cannel开源框架)
- 审计(audit):用户可以通过二进制日志中的信息进行审计,判断是否有对数据库进行注入的攻击。
mysql复制原理
- master在每个事务更新数据完成之前,将该操作记录串行地写入到binlog文件中,也称为二进制文件。
- slave开启一个I/O Thread,该线程与master建立连接,master则会启动binlog dump 线程并取binlog事件。如果读取的进度已经跟上了master,就进入睡眠状态并等待master产生新的事件。salve的I/O线程将接收到的事件写入到relay log(中继日志)中,且slave连接master的信息及同步进度数据都会保存在master.info文件中(具体内容参考下面复制方式)。
- slave 中的 SQL Thread会读取relay log(中继日志),并顺序执行该日志中的SQL事件,从而与主数据库中的数据保持一致。
mysql复制模式
- ROW(行模式):记录那条数据修改了,注意:记录的是这条记录的全部数据,即使只更新了一个字段,binlog里也会记录所有字段的数据
- 优点:他不记录sql语句的上下文信息,日志内容会非常清楚的记录每条数据详细的变更细节,即使只更新了一个字段,binlog里也会记录所有字段的数据。因为可靠性强,基本选成这种
- 缺点:binlog日志会非常大,mysql主从同步时,会产生大量磁盘IO
- Statement(语句模式): 每一条会修改数据的sql都会记录在binlog中。
- 优点:不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能。
- 缺点:由于记录的只是执行语句,为了这些语句能在slave上正确运行,因此还必须记录每条语句在执行的时候的一些相关信息,以保证所有语句能在slave得到和在master端执行时候相同 的结果。另外mysql 的复制,像一些特定函数功能,slave可与master上要保持一致会有很多相关问题。
- Mixed(混合模式):在Mixed模式下,一般的语句修改使用statment格式保存binlog,如一些函数,statement无法完成主从复制的操作,则采用row格式保存binlog,MySQL会根据执行的每一条具体的sql语句来区分对待记录的日志形式,也就是在Statement和Row之间选择一种。
MySQL主从复制方式
前提:binlog文件是顺序存储结构的。
- 基于日志点复制
- 时间time,根据时间找time到binlog文件中与此时间最近的事务pos进行同步
- 位置pos,根据位置pos找到binlog文件中与此位置最近的事务pos进行同步
- 基于GTID复制
- GTID是全局事务ID,其保证为每个在master上提交的事务在复制集群中可以生产一个唯一ID。GTID的生成策略是source_id(也就是server的uuid,在auto.conf文件里面可以看到):transaction_id(自增序列)。解决Master-Master拓扑模式,binlog回路问题
- 根据gtid,直接在binlog文件中找到进行同步
区别
- 基于日志点复制
- 对sql查询没有什么限制
- 故障转移时重新获取master的日志点信息比较困难(因为偏移点是批量增长的,时间的话有可能一样)。如果指定错误会造成遗漏或者重复,造成主从不一致。
- 基于GTID复制
- 不支持非事务引擎。对执行的sql有一定的限制。
- 可以很方便的进行故障转移,记录master最后事务的GTID值。(按事务分,比较清晰)
Mysql复制类型
- MySQL 5.5版本之前,一直采用的是这种异步复制的方式。主库的事务执行不会管备库的同步进度,如果备库落后,主库不幸crash,那么就会导致数据丢失.
- 在MySQL在5.5中就顺其自然地引入了半同步复制,主库在应答客户端提交的事务前需要保证至少一个从库接收并写到relay log中。
- MySQL在5.7.17中引入了一个全新的技术,称之为InnoDB Group Replication。目前官方MySQL 5.7.17基于Group replication的全同步技术已经问世,全同步技术带来了更多的数据一致性保障
异步复制
MySQL默认的复制即是异步的.
- 主库将事务Binlog事件写入到Binlog文件中
- 主库通知一下Dump线程发送这些新的Binlog
- 主库就会继续处理提交操作(sync binlog, engine Commit)
- 返回客户端(此时不会保证这些Binlog传到任何一个从库节点上)
最大的问题
master和slave事务更新的不同步,当业务并发上来时,slave因为要顺序执行master批量事务,导致很大的延迟。此时,master如果crash掉了,master上已经提交的事务可能没有传到slave上,如果此时,强行将从提升为主,可能导致新主上的数据不完整。
半同步复制
为解决异步复制的不足,MySQL 5.5~5.6可安装semisync_master.so插件,使用after_commit模式的半同步复制
- 主库将事务Binlog事件写入到Binlog文件中
- 主库通知一下Dump线程发送这些新的Binlog
- 主库就会继续处理提交操作(sync binlog, engine Commit),并向从库发生Event。
- dumper线程等待接收slave的ack工作
- 返回客户端
最大的问题
主库将事务在存储引擎层(engine Commit)提交后,主库发生了crash,Slave端还没有读到该事务的events。此时,虽然主库没有返回当前客户端,但事务已经提交,其他客户端会读取到已提交事务。现在强行将从提升为主,那么之前读到的事务就不见了,出现了幻读。
针对上述的问题,5.7.2引入了Loss-less Semi-Synchronous插件,支持after_sync模式的半同步复制
6. 主库将事务Binlog事件写入到Binlog文件中
7. 主库通知一下Dump线程发送这些新的Binlog
8. 主库就会继续处理提交操作(sync binlog),并向从库发生Event。
9. Receiver线程等待接收slave的ack工作
10. 主库就会继续处理提交操作engine Commit
11. 返回客户端
两者区别
- 独立出一个Ack Receiver线程 ,专门用于接收slave返回的ack请求,这将之前dump线程的发送和接受工作分为了两个线程来处理。
- 无损复制在write binlog完成后,就传输binlog,但还没有去写commit log,意味着当前这个事物对数据库的修改,其他事物也是不可见的。因此,不会出现幻读,数据丢失风险。
实际使用中还碰到一种情况从库IO线程有延迟时,主库会自动把半同步复制降为异步复制;当从库IO延迟没有时,主库又会把异步复制升级为半同步复制。
全同步复制
又称组复制。基于传统异步复制和半同步复制的缺陷——数据的一致性问题无法保证,官方在5.7.17版本正式推出组复制(MySQL Group Replication,简称MGR)。
MGR依靠分布式一致性Paxos协议(变体),实现了分布式下数据的最终一致性,并且所有以前特点(功能可参考《日志一致性协议Raft》)
- 高可用:一台机子挂了,其它正常
- 可扩展:可加节点,新加节点会同步老节点数据(必须基于GTID)
- 容错:容忍 f 个故障机所需的服务器数量 n 为:n = 2 * f + 1。
mysql复制常用拓扑结构
复制的体系结构有以下一些基本原则:
- 每个slave只能有一个master;
- 每个slave只能有一个唯一的服务器ID;
- 每个master可以有很多slave;
- 如果你设置log_slave_updates,slave可以是其它slave的master,从而扩散master的更新。
常见的拓扑结构有:
- master和slave
- 主动-被动模式的Master-Master
- 带从服务器的Master-Master结构
- master和分发master和slave
- 级联复制架构 Master –Slaves - Slaves
备份恢复
“复制是备份”是我们经常碰到一个误区,复制不是备份。如果意外发生主库"drop database",备库能否帮我们恢复所有的数据?而我们的备份方案往往是根据恢复需求而来的。
备份方案
-
逻辑备份还是物理备份
- 逻辑备份:由数据库服务器完成生成逻辑备份,比如dump将表以sql 的方式导出
- 物理备份:基于文件,只需要将需要的文件复制到其他地方即可完成备份,比如binlog。InnoDB需要停止数据库服务(FLUSH TABLES WITH READ LOCK)把缓存中的数据都刷到磁盘,或者直接关停Mysql
-
在线备份还是离线备份
- 离线备份:将Mysql关停,备份数据(大多情况无法接受)
- 物理备份:Mysql运行期间进行备份,大致要考虑
- 锁时间:需要持有锁多长时间,例如备份期间持有的全局FLUSH TABLES WITH READ LOCK。将数据导出
- 备份时间和负载: 复制备份到目的地需要多久及对服务器性能的影响有多少(Perconna XtraBackup工具有控流产品)
- 恢复时间:把备份镜像从存储位置复制到MySQL服务器,重放二进制日志需要多久
-
快照方式
- 复制数据文件产生副本
- 文件系统快照,LVM
- 硬盘快照,RAID
-
全量备份还是增量备份
- 全量备份:全部备份下来
- 增量备份:上次全量备份后,所发生改变的数据进行备份
互联网复制备份架构选择
- 复制拓扑采用主动-被动模式的Master-Master
- 在被动Master(备库)使用 XtraBackup 进行 每周全量,第日增量的物理备份
- 在被动Master(备库),接入canal等开源框架并向其它库分发(模拟从库)
满足以下问题:
- 选择性复制:模拟从库可以根据自己的需要拉取相关数据
- 分离功能:Master只做OLTP.OLAP在模拟从库做
- 数据归档:模拟从库,可不接收Master的delete事件。Master最好保证逻辑设计,由DBA统一删除。最好使用唯一的ID,以防止归档的时间出现错误
- 文件系统快照:停机被动Master,全量备份Mysql数据文件.然后再flush logs,将后面提交的写到新的binlog中,方便增量备份。
- 数据一致性:binlog事件是基于事务的,不能防止逻辑设计很差的应用 (本来是业务要求一个事件,开发者设计成两个或以上事务,破坏数据一致性)
主要参考
《高性能Mysql》
《MySQL 5.7半同步复制技术》
《MySQL 8 复制(七)——组复制基本原理》