器 | Mysql基于GTID的主从同步原理

1,602 阅读5分钟

这是我参与更文挑战的第14天,活动详情查看: 更文挑战

前面已经有一篇文章成功实践了基于GTIDMysql主主同步。但是原理性的东西还不是很了解,比如什么是GTID?主从同步的流程是怎样的?GTID的优缺点分别是什么?代入这些问题,我们来了解一下原理。

1.主从同步流程

1.1相关概念解释

InnoDB 使用undoredo log 来保证事务原子性、一致性及持久性,同时采用预写日志(Write-Ahead Logging)方式将随机写入变成顺序追加写入,提升事务性能。

binglog 二进制日志,也称归档日志

binlog日志用于记录所有更新且提交了数据或者已经潜在更新提交了数据的所有数据。用于主从同步和基于时间节点还原。

redolog 重做日志

记录事务将要变更后的状态。事务提交时,只要将redo log 持久化即可,数据可在内存中变更。当系统崩溃时,虽然数据没有落盘,但是redo log 已持久化,系统可以根据redo log 的内容,将所有数据恢复到最新的状态。

undolog 回滚日志

记录事务变更前的状态。操作数据之前,先将数据备份到undo log ,然后进行数据修改,如果出现错误或用户执行了rollback 语句,则系统就可以利用undo log 中的历史版本恢复到事务开始之前的状态。

1.2 流程解析

主备同步流程图(借鉴一下网上的图片,后续替换)

下载.png

主库接收到客户端的更新请求后,执行内部事务的更新逻辑,同时写binlog

备库B跟主库A之间维持了一个长连接。主库A内部有一个线程,专门用于服务备库B的这个长连接。一个事务日志同步的完整过程是这样的:

在备库B上通过change master命令,设置主库A的IP、端口、用户名、密码,以及要从哪个位置开始请求binlog,这个位置包含文件名和日志偏移量。 在备库B上执行start slave命令,这时候备库会启动两个线程,就是图中的io_thread和sql_thread。其中io_thread负责与主库建立连接。 主库A校验完用户名、密码后,开始按照备库B传过来的位置,从本地读取binlog,发给B。 备库B拿到binlog后,写到本地文件,称为中转日志(relay log)。 sql_thread读取中转日志,解析出日志里的命令,并执行。 Tip:多线程复制方案的引入,sql_thread演化成为了多个线程

2.GTID讲解

2.1 GTID是什么

GTID的全称是Global Transaction Identifier,也就是全局事务ID,是一个事务在提交的时候生成的,是这个事务的唯一标识。它由两部分组成,格式是:

GTID=source_id:transaction_id

其中:

server_uuid是一个数据库实例第一次启动时自动生成的,是一个全局唯一的值; transaction_id是一个整数,初始值是1,每次提交事务的时候分配给这个事务,并加1。 此时的transaction_id并不是我们平时使用的事务id,事务id是在事务执行过程中分配的,如果这个事务回滚了,事务id也会递增。而此时的transaction_id是在事务提交的时候才会分配,所以GTID往往是连续的。

2.2 GTID的生成方式

GTID有两种生成方式,而使用哪种方式取决于session变量gtid_next的值。

GTID模式下,每个事务都会跟一个GTID一一对应。这个GTID有两种生成方式,而使用哪种方式取决于session变量gtid_next的值。

如果gtid_next=automatic,代表使用默认值。这时,MySQL就会把server_uuid:gno分配给这个事务。

  • a. 记录binlog的时候,先记录一行 SET @@SESSION.GTID_NEXT=‘server_uuid:gno’;
  • b. 把这个GTID加入本实例的GTID集合。 如果gtid_next是一个指定的GTID的值,比如通过set gtid_next=’current_gtid’指定为current_gtid,那么就有两种可能:
  • a. 如果current_gtid已经存在于实例的GTID集合中,接下来执行的这个事务会直接被系统忽略;
  • b. 如果current_gtid没有存在于实例的GTID集合中,就将这个current_gtid分配给接下来要执行的事务,也就是说系统不需要给这个事务生成新的GTID,因此gno也不用加1。 一个current_gtid只能给一个事务使用。这个事务提交后,如果要执行下一个事务,就要执行set 命令,把gtid_next设置成另外一个gtid或者automatic。

每个MySQL实例都维护了一个GTID集合,用来对应“这个实例执行过的所有事务

2.3开启GTID方式

在启动数据库实例的时候,配置以下参数即可

enforce_gtid_consistency=on
gtid_mode=on

注意以上参数缺一不可

2.4 GTID优缺点

优点

  • 搭建主从同步便捷

slave 做同步设置时,只需要设置change master to master_auto_position=1即可,无须通过在master执行 show master status找binlog日志名称和POSITION点,MySQL会通过内部机制GTID自动找点同步。

  • 支持多线程复制(基于库)

在Mysql5.6之前,Salve复制是单线程的,一个事件一个事件的读取应用,但客户端并发写入Master时候,会造成从库同步延迟。在MySQL 5.6里面,我们可以把多个表放在多个库,这样就可以使用多线程复制,当只有1个库,多线程复制是没有用的

  • 强大的failover能力

当Master crash时,Salve必然面临切换到Master,GTID提供强大的故障恢复能力

处理主从数据冲突方便,在从库提交空事务的方式进行跳过

缺点

  • 不支持非事务引擎

CREATE TABLE …SELECT,临时表等语句不支持

该语句会被拆分成createtable 和insert两个事务,并且这个两个事务被分配了同一个GTID,这会导致insert被备库忽略掉;

  • 存在Errant transaction

也就是没有规范的从master执行,而是直接从slave执行的事务。需要尽量避免此类事务,如果非要在slave上写数据时,通过关闭log bin解决。如果出现了此类情况,可以根据具体情况执行空事务(重复键值)或者重做SlaveSlave多执行了事务)解决问题。