a) GTID = server_uuid:transaction_id
b) server_uuid 来源于 auto.cnf
c) GTID: 在一组复制中,全局唯一
gtid_set:
uuid_set [, uuid_set] ...
| ''
uuid_set:
uuid:interval[:interval]...
uuid:
hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh
h:
[0-9|A-F]
interval:
n[-n]
(n >= 1)
- Previous_gtid_log_event 在每个binlog 头部都会有
- 每次binlog rotate的时候存储在binlog头部
- Previous-GTIDs在binlog中只会存储在这台机器上执行过的所有binlog,不包括手动设置gtid_purged值。
- 换句话说,如果你手动set global gtid_purged=xx; 那么xx是不会记录在Previous_gtid_log_event中的。
如何才能找到GTID=?对应的binlog文件呢?
* 假设有4个binlog: bin.001,bin.002,bin.003,bin.004
* bin.001 : Previous-GTIDs=empty; binlog_event有:1-40
* bin.002 : Previous-GTIDs=1-40; binlog_event有:41-80
* bin.003 : Previous-GTIDs=1-80; binlog_event有:81-120
* bin.004 : Previous-GTIDs=1-120; binlog_event有:121-160
1. 假设现在我们要找GTID=$A,那么MySQL的扫描顺序为: 从最后一个binlog开始扫描(即:bin.004)
2. bin.004的Previous-GTIDs=1-120,如果$A=140 > Previous-GTIDs,那么肯定在bin.004中
3. bin.004的Previous-GTIDs=1-120,如果$A=88 包含在Previous-GTIDs中,那么继续对比上一个binlog文件 bin.003,然后再循环前面2个步骤,直到找到为止
参数 | comment |
---|---|
gtid_executed | 执行过的所有GTID |
gtid_purged | 丢弃掉的GTID |
gtid_mode | gtid模式 |
gtid_next | session级别的变量,下一个gtid |
gtid_owned | 正在运行的gtid |
enforce_gtid_consistency | 保证GTID安全的参数 |
1) 如何持久化gtid_executed [ log-bin=on,log_slave_update=on ]
1. gtid_executed = mysql.gtid_executed 【normal】
or
2. gtid_executed = mysql.gtid_executed + last_binlog中最后没写到mysql.gtid_executed中的gtid_event 【recover】
2) 如何持久化重置的gtid_purged值?
reset master; set global gtid_purged=$A:a-b;
1. 由于有可能手动设置过gtid_purged=$A:a-b, binlog.index中,last_binlog的Previous-GTIDs并不会包含$A:a-b
2. 由于有可能手动设置过gtid_purged=$A:a-b, binlog.index中,first_binlog的Previous-GTIDs肯定不会出现$A:a-b
3. 重置的gtid_purged = @@global.gtid_executed(mysql.gtid_executed:注意,考虑到这个表的更新触发条件,所以这里用@@global.gtid_executed代替) - last_binlog的Previous-GTIDs - last_binlog所有的gtid_event
4. 下面就用 $reset_gtid_purged 来表示重置的gtid
3)如何持久化gtid_purged [ log-bin=on,log_slave_update=on ]
gtid_purged=binlog.index:first_binlog的Previous-GTIDs + $reset_gtid_purged
gtid_mode=ON(必选)
log_bin=ON(必选)
log-slave-updates=ON(必选)
enforce-gtid-consistency(必选)
MySQL5.7.13 or higher
gtid_mode=ON(必选)
enforce-gtid-consistency(必选)
log_bin=ON(可选)--高可用切换,最好设置ON
log-slave-updates=ON(可选)--高可用切换,最好设置ON
slave1 : 将自身的UUID1:1 发送给 master,然后接收到了 UUID1:2,UUID1:3 event
slave2 : 将自身的UUID1:1,UUID1:2 发送给 master,然后接收到了UUID1:3 event
Name | Description |
---|---|
GTID_SUBSET(subset,set) | returns true (1) if all GTIDs in subset are also in set |
GTID_SUBTRACT(set,subset) | returns only those GTIDs from set that are not in subset |
WAIT_FOR_EXECUTED_GTID_SET(gtid_set[, timeout]) | Wait until the given GTIDs have executed on slave. |
WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS(gtid_set, timeout) | Wait until the given GTIDs have executed on slave |
START SLAVE [thread_types] [until_option] [connection_options]
thread_types:
[thread_type [, thread_type] ... ]
thread_type:
IO_THREAD | SQL_THREAD
until_option:
UNTIL { {SQL_BEFORE_GTIDS | SQL_AFTER_GTIDS} = gtid_set
| MASTER_LOG_FILE = 'log_name', MASTER_LOG_POS = log_pos
| RELAY_LOG_FILE = 'log_name', RELAY_LOG_POS = log_pos
| SQL_AFTER_MTS_GAPS }
* 举个栗子:
1. START SLAVE SQL_THREAD UNTIL SQL_BEFORE_GTIDS = 3E11FA47-71CA-11E1-9E33-C80AA9429562:11-56
表示,当SQL_thread 执行到3E11FA47-71CA-11E1-9E33-C80AA9429562:10 的时候停止,下一个事务是11
2. START SLAVE SQL_THREAD UNTIL SQL_AFTER_GTIDS = 3E11FA47-71CA-11E1-9E33-C80AA9429562:11-56
表示,当SQL_thread 执行到3E11FA47-71CA-11E1-9E33-C80AA9429562:56 的时候停止,56是最后一个提交的事务。
设置enforce-gtid-consistency=ON
1. CREATE TABLE ... SELECT statements
2. CREATE TEMPORARY TABLE or DROP TEMPORARY TABLE statements inside transactions
3. 同时更新 事务引擎 和 非事务引擎。
http://dev.mysql.com/doc/refman/5.7/en/replication-solutions-unexpected-slave-halt.html
关于crash safe , 可以参考官方文档列出的安全配置
Non-GTID 推荐配置: relay_log_recovery=1,relay_log_info_repository=TABLE,master_info_repository=TABLE
GTID 推荐配置:MASTER_AUTO_POSITION=on,relay_log_recovery=0
Non-GTID 推荐配置: relay_log_recovery=1, sync_relay_log=1,relay_log_info_repository=TABLE,master_info_repository=TABLE
GTID 推荐配置: MASTER_AUTO_POSITION=on, relay_log_recovery=0
mysql> SET @@global.read_only = ON;
shell> mysqladmin -uusername -p shutdown
shell> mysqld --gtid-mode=ON --log-bin --enforce-gtid-consistency &
当然,在my.cnf中配置好最佳
mysql> CHANGE MASTER TO
> MASTER_HOST = host,
> MASTER_PORT = port,
> MASTER_USER = user,
> MASTER_PASSWORD = password,
> MASTER_AUTO_POSITION = 1;
mysql> START SLAVE;
mysql> SET @@global.read_only = OFF;
mysqldump xx 获取并且记录gtid_purged值
or
冷备份 --获取并且记录gtid_executed值,这个就相当于mysqldump中得到的gtid_purged
reset master; --清空gtid信息
导入备份; --如果是逻辑导入,请设置sql_log_bin=off
set global gtid_purged=xx;
mysql> CHANGE MASTER TO
> MASTER_HOST = host,
> MASTER_PORT = port,
> MASTER_USER = user,
> MASTER_PASSWORD = password,
> MASTER_AUTO_POSITION = 1;
mysql> START SLAVE;
offline 的方式升级最简单。全部关机,然后配置好GTID,重启,change master to MASTER_AUTO_POSITION=1。
这里先介绍几个重要GTID_MODE的value
水平的GTID_MODE为:master , 垂直的GTID_MODE为:slave
gtid_mode | OFF(master) | OFF_PERMISSIVE(master) | ON_PERMISSIVE(master) | ON(master) |
---|---|---|---|---|
OFF(slave) | Y | Y | N | N |
OFF_PERMISSIVE(slave) | Y | Y | Y | Y(auto_position可以开启) |
ON_PERMISSIVE(slave) | Y | Y | Y | Y(auto_position可以开启) |
ON(slave) | N | N | Y | Y(auto_position可以开启) |
归纳总结:
1) 当master产生Normal_GTID的时候(ON_PERMISSIVE,ON),如果slave的gtid_mode(OFF)不能接受Normal_GTID,那么就会报错
2) 当master产生ANONYMOUS_GTID的时候(OFF_PERMISSIVE,OFF),如果slave的gtid_mode(ON)不能接受ANONYMOUS_GTID,那么就会报错
3) 设置auto_position的条件: 当master gtid_mode=ON时,slave可以为OFF_PERMISSIVE,ON_PERMISSIVE,ON。除此之外,都不能设置auto_position = on
下面罗列下,如何online 升级为GTID模式。
检查错误日志,直到没有错误出现,才能进行下一步
SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = WARN;
SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = ON;
不用关心一组复制集群的server的执行顺序,只需要保证每个Server都执行了,才能进行下一步
SET @@GLOBAL.GTID_MODE = OFF_PERMISSIVE;
不用关心一组复制集群的server的执行顺序,只需要保证每个Server都执行了,才能进行下一步
SET @@GLOBAL.GTID_MODE = ON_PERMISSIVE;
不需要一直为0,只要出现过0一次,就ok
SHOW STATUS LIKE 'ONGOING_ANONYMOUS_TRANSACTION_COUNT';
1. master
SHOW MASTER STATUS;
2. 每个slave
SELECT MASTER_POS_WAIT(file, position);
或者,等一段时间,只要不是大的延迟,一般都没问题
SET @@GLOBAL.GTID_MODE = ON;
gtid_mode=ON(必选)
enforce-gtid-consistency(必选)
log_bin=ON(可选)--高可用切换,最好设置ON
log-slave-updates=ON(可选)--高可用切换,最好设置ON
STOP SLAVE;
CHANGE MASTER TO MASTER_AUTO_POSITION = 1;
START SLAVE;
配置好loss-less semi-sync replication,可以更可靠的保证数据零丢失。
以下说的都是crash 后,起不来的情况
1. 选取最新的slave,change master to maseter_auto_position同步好
2. mysqlbinlog 将没传递过来的binlog在新master上replay
3. 打开新master的surper_read_only=off;
1. 选取最新的slave,change master to maseter_auto_position同步好
2. 打开新master的surper_read_only=off;
1. 选取最新的slave,change master to maseter_auto_position同步好
2. 打开新master的surper_read_only=off;
以上操作,在传统模式复制下,只能通过MHA来实现,MHA比较复杂。
现在,在GTID模式下,实现起来非常简单,且非常方便。
- 使用GTID后,对原来传统的运维有不同之处了,需要调整过来。
- 使用Row模式且复制配置正确的情况下,基本上很少发现有复制出错的情况。
- slave 设置 super_read_only=on
出现这种问题基本有两种情况
- 复制参数没有配置正确,当slave crash后,会出现重复键问题
- DBA操作不正确,不小心在slave上执行了事务
对于第一个重复键问题
* skip transation;
SQL> SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
SQL> START SLAVE;
SQL> SET GTID_NEXT='b9b4712a-df64-11e3-b391-60672090eb04:7'; --设置需要跳过的gtid event
SQL> BEGIN;COMMIT;
SQL> SET GTID_NEXT='AUTOMATIC';
SQL> START SLAVE;
对于第二种不小心多执行了事务
这种情况就比较难了,这样已经导致了数据不一致,大多数情况,建议slave重做
如何避免: slave 设置 super_read_only=on
这里说下inject empty transction的隐患
目前只能够reset master
* 当gtid_executed 非空的时候,不能设置gtid_purged
* 当gtid_executed 为空的时候(即刚刚备份好的镜像,刚搭建的mysql),可以直接SET @@GLOBAL.GTID_PURGED='0ad6eae9-2d66-11e6-864f-ecf4bbf1f42c:1-3';
如果被删掉,重启后,server-uuid 会变
不会
可以,改过滤的会自己过滤,不用担心