天天看点

MySQL内核月报 2014.09-MySQL· 限制改进·GTID和升级

<b>gtid 资料</b>

mysql 5.6 引入了global transaction identifiers (gtids,全局事务id)的特性,这一特性是用来解决主从复制(replication)场景下的一些问题,gtid 只存在于 binlog 中,数据库中是没有的。

<a href="http://svenmysql.blogspot.se/2012/10/failover-and-flexible-replication.html">failover and flexible replication topologies in mysql 5.6</a>

<a href="http://svenmysql.blogspot.jp/2012/10/advanced-use-of-global-transaction.html">advanced use of global transaction identifiers</a>

<a href="http://svenmysql.blogspot.jp/2013/03/flexible-fail-over-policies-using-mysql.html">flexible fail-over policies using mysql and global transaction identifiers</a>

<b>升级遇到的问题</b>

gtid 能很好的解决 failover 问题,做到主库切换自动化,减轻 dba 同学的负担,但是这个前提是所有的 mysql 实例都是 5.6,如果线上实例是 5.5 的,必须全部升到 5.6 才行,而目前官方并没有提供平滑的 5.5 升级到 5.6 gtid 的方式,中间必须要有一个实例重启过程,这是由 gtid 目前的实现方式决定的:

限制1. gtid 模式实例和非gtid模式实例是不能进行复制的,要求非常严格,一刀切,要么都是gtid,要么都不是

限制2. gtid_mode 是只读的,要改变状态必须1)关闭实例、2)修改配置文件、3) 重启实例

在这种条件要求下,我们来看下线上实例从 5.5 升级到 5.6 会有什么问题,为了保证业务不中断,升级过程一直要有实例对外提供服务,因此升级方式是创建一个新的 5.6 实例,从5.5同步数据,然后业务切换到 5.6。

为了描述方便,做如下假设:

<dl></dl>

<dt>实例a</dt>

<dd>5.5 版本的,目前业务用的数据库</dd>

<dt>实例b</dt>

<dd>5.6 版本的,数据迁移的目标</dd>

迁移步骤如下:

用热备份工具如 percona xtrabackup 将 a 数据备份然后导入到b

b 用非 gtid 模式和 5.5 同步数据,这时用的是传统的基于文件位置的复制

b和a同步的差不多的时候,在 a 上设 read_only,等 b 同步完成,假设同步完后时间点为 t1

关闭 b,修改参数开启gtid,重启b

将业务的数据操作指向b,假设这个时间点为 t2

b 开始提供服务,迁移完毕

在上面的步骤中,t1 到 t2 的时间段内相当于数据库服务不可用,整个数据库停掉重启,这对线上业务来说是不可接受的,上面是用单个实例a和实例b说明问题,同样可以扩展到集群a和集群b。

gtid_mode 的取值范围除了 off 和 on 这两个值外,还有 upgrade_step_1和upgrade_step_2,目前后2者并不支持,不过从名字上看应该是为了升级预留的,但是目前并没有好的升级方式。

<b>解决方案</b>

之前的升级方式是 a-&gt;b 这种拓扑,现在变为 a-&gt;c-&gt;b

<dt>实例c</dt>

<dd>5.6 版本的,一种中间状态实例,既可以和非gtid通信,又可以和gtid通信</dd>

建立 a-&gt;c-&gt;b 这种复制关系,其中 a-&gt;c 之间是文件位置协议,c-&gt;b 之间是 gtid 协议

b、c和a同步的差不多的时候,在 a 上设 read_only,等b同步完成

将业务的数据操作指向b

这里为了和之前迁移目标一致,多用了一个实例c,其实这时候可以把b给去掉,还是2个实例。可以看到,引入了c后,升级过程中并没有实例重启过程,只有一个短暂的只读时间段,这个是无法避免的,即使不用gtid,也会有这个过程。

目前rds实例升级到5.6也是用这种方式。如果是集群到集群的话,要注意一点,处于中间状态的实例c最好只有一个,因为这种实例相当于一个gtid转换器,将a中没有 gtid 的 binlog 转成包含 gtid 的 binlog,然后传给b,如果有多个实例c的话,a中同一个binlog 中的事务会转换出不同的gtid,这与 gtid 和事务一一对应的根本原则相矛盾,复制会出问题。当然,如果能保证经过不同的c的binlog事务不会重复的话就可以有多个c。