在GTID-based复制中,如何扩容一个只读实例?


这里使用mysqldump工具在Master节点上进行数据备份,注意一个关键参数:--set-gtid-purged[=name],该参数代表在备份文件中,哪些GTID已执行过了,在change master时,复制将从这些GTID之后进行。


--set-gtid-purged[=name]

Add 'SET @@GLOBAL.GTID_PURGED' to the output. Possible

values for this option are ON, OFF and AUTO. If ON is

used and GTIDs are not enabled on the server, an error is

generated. If OFF is used, this option does nothing. If

AUTO is used and GTIDs are enabled on the server, 'SET

@@GLOBAL.GTID_PURGED' is added to the output. If GTIDs

are disabled, AUTO does nothing. If no value is supplied

then the default (AUTO) value will be considered.


mysqldump命令如下:


$ bin/mysqldump --user=root --password='123456' --socket=/home/mysql/mysql3309/tmp/mysql.sock --default-character-set=utf8mb4 --events --routines --triggers --force --hex-blob --quick --single-transaction --set-gtid-purged=ON --databases db1 lg > /tmp/bak/data.sql

Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions, even those that changed suppressed parts of the database. If you don't want to restore GTIDs, pass --set-gtid-purged=OFF. To make a complete dump, pass --all-databases --triggers --routines --events. 



观察备份文件data.sql,会发现两处值得注意的地方:


·使用备份文件导入数据时,将会话级系统变量@@SESSION.SQL_LOG_BIN设置为了0,即不产生二进制日志。

SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN;

SET @@SESSION.SQL_LOG_BIN= 0;

...

SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN;


·设置了全局系统变量@@GLOBAL.GTID_PURGED。

SET @@GLOBAL.GTID_PURGED='0c34233d-b2e1-11e9-85cf-080027f22add:1-2,

32a0c858-b59f-11e9-b069-0800270c3d91:1-2,

447e96e1-b59f-11e9-95fe-0800270c3d91:1-2,

4fdc13e1-b59e-11e9-b5e0-080027f22add:1-9,

b8282f18-b59e-11e9-83b0-0800270c3d91:1-5';


同时也设置了@@GLOBAL.GTID_EXECUTED,这就是复制从何处开始的依据。确切的说是,@@GLOBAL.GTID_EXECUTED为空时,才能设置@@GLOBAL.GTID_PURGED,否则报错如下。同时@@GLOBAL.GTID_EXECUTED会设置成和@@GLOBAL.GTID_PURGED具有相同的值。


ERROR 1840 (HY000): @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.

Query OK, 1 row affected (0.00 sec)


导入备份数据前,观察新Slave节点上@@GLOBAL.GTID_PURGED,和@@GLOBAL.GTID_EXECUTED的值。

[[email protected]][(none)]> select @@GLOBAL.GTID_PURGED;

+----------------------+

| @@GLOBAL.GTID_PURGED |

+----------------------+

|                      |

+----------------------+

1 row in set (0.00 sec)


[[email protected]][(none)]> 

[[email protected]][(none)]> select @@GLOBAL.GTID_EXECUTED;

+------------------------+

| @@GLOBAL.GTID_EXECUTED |

+------------------------+

|                        |

+------------------------+

1 row in set (0.00 sec)


导入数据后,再观察。

[[email protected]][(none)]> source /tmp/bak/data.sql;

...


[[email protected]][lg]> select @@GLOBAL.GTID_PURGED;

+-------------------------------------------------+

| @@GLOBAL.GTID_PURGED |

+-------------------------------------------------+

| 0c34233d-b2e1-11e9-85cf-080027f22add:1-2,

32a0c858-b59f-11e9-b069-0800270c3d91:1-2,

447e96e1-b59f-11e9-95fe-0800270c3d91:1-2,

4fdc13e1-b59e-11e9-b5e0-080027f22add:1-9,

b8282f18-b59e-11e9-83b0-0800270c3d91:1-5 |

+-------------------------------------------------+

1 row in set (0.00 sec)


[[email protected]][lg]> select @@GLOBAL.GTID_EXECUTED;

+-------------------------------------------------+

| @@GLOBAL.GTID_EXECUTED |

+-------------------------------------------------+

| 0c34233d-b2e1-11e9-85cf-080027f22add:1-2,

32a0c858-b59f-11e9-b069-0800270c3d91:1-2,

447e96e1-b59f-11e9-95fe-0800270c3d91:1-2,

4fdc13e1-b59e-11e9-b5e0-080027f22add:1-9,

b8282f18-b59e-11e9-83b0-0800270c3d91:1-5 |

+-------------------------------------------------+

1 row in set (0.00 sec)


最后change master即可。

CHANGE MASTER TO

MASTER_HOST='10.0.2.6',

MASTER_USER='repl',

MASTER_PASSWORD='123456',

MASTER_PORT=3309,

MASTER_AUTO_POSITION = 1;


注意,在一些特殊场景下,可能需要手动设置@@GLOBAL.GTID_PURGED。



在GTID-based的复制中,如何设置级联复制呢,要求复制拓扑如下,其中箭头代表数据的复制方向,括号中的部分还不存在。


S <- M (-> M' -> S')


若先建立M' -> S'的复制关系,使用mysqldump在M上备份数据,然后导入M',数据会从M'复制到S'吗,通过上面知道,导入数据时设置了@@SESSION.SQL_LOG_BIN= 0,所以数据不会从M'复制到S',这点是和Position-based复制不一样的,即如下方式不会设置SQL_LOG_BIN。


$ bin/mysqldump --user=root --password='123456' --socket=/home/mysql/mysql3309/tmp/mysql.sock --default-character-set=utf8mb4 --events --routines --triggers --force --hex-blob --quick --single-transaction --set-gtid-purged=OFF --master-data=2 --databases db1 lg > /tmp/bak/2data.sql


所以正确的思路是,用备份数据同时恢复M'和S',然后建立M' -> S',最后建立M -> M'。



对于Failover,由于不需要指定位点信息,直接change master即可,比Position-based复制简洁很多。另,通过前面几篇文章的介绍,也可以发现GTID-based的复制比Position-based复制在数据一致性方面更加严格,不像Position-based复制随便指定个位点,若复制过程无报错,就可以继续。



PS:使用xtrabackup备份数据时,上面的思路是完全成立的。