- GTID简介
- 搭建
- 实验一:如果slave所需要事务对应的GTID在master上已经被purge了
- 实验二:忽略purged的部分,强行同步
本文将简单介绍基于5.6 GTID的主从复制原理的搭建。并通过几个实验介绍相关故障的处理方式
GTID简介
什么是GTID
GTID(Global Transaction ID)是对于一个已提交事务的编号,并且是一个全局唯一的编号。 GTID实际上是由UUID+TID组成的。其中UUID是一个MySQL实例的唯一标识。TID代表了该实例上已经提交的事务数量,并且随着事务提交单调递增。下面是一个GTID的具体形式
3E11FA47-71CA-11E1-9E33-C80AA9429562:23
更详细的介绍可以参见:官方文档
GTID的作用
那么GTID功能的目的是什么呢?具体归纳主要有以下两点:
- 根据GTID可以知道事务最初是在哪个实例上提交的
- GTID的存在方便了Replication的Failover
这里详细解释下第二点。我们可以看下在MySQL 5.6的GTID出现以前replication failover的操作过程。假设我们有一个如下图的环境 此时,Server A的服务器宕机,需要将业务切换到Server B上。同时,我们又需要将Server C的复制源改成Server B。复制源修改的命令语法很简单即CHANGE MASTER TO MASTER_HOST='xxx', MASTER_LOG_FILE='xxx', MASTER_LOG_POS=nnnn。而难点在于,由于同一个事务在每台机器上所在的binlog名字和位置都不一样,那么怎么找到Server C当前同步停止点,对应Server B的master_log_file和master_log_pos是什么的时候就成为了难题。这也就是为什么M-S复制集群需要使用MMM,MHA这样的额外管理工具的一个重要原因。 这个问题在5.6的GTID出现后,就显得非常的简单。由于同一事务的GTID在所有节点上的值一致,那么根据Server C当前停止点的GTID就能唯一定位到Server B上的GTID。甚至由于MASTER_AUTO_POSITION功能的出现,我们都不需要知道GTID的具体值,直接使用CHANGE MASTER TO MASTER_HOST='xxx', MASTER_AUTO_POSITION命令就可以直接完成failover的工作。 So easy不是么?
搭建
本次搭建使用了mysql_sandbox脚本为基础,先创建了一个一主三从的基于位置复制的环境。然后通过配置修改,将整个架构专为基于GTID的复制。如果你还不熟悉mysql_sandbox,可以阅读博客之前的文章博客之前的文章一步步的安装。 根据MySQL官方文档给出的GTID搭建建议。需要一次对主从节点做配置修改,并重启服务。这样的操作,显然在production环境进行升级时是不可接受的。Facebook,Booking.com,Percona都对此通过patch做了优化,做到了更优雅的升级。具体的操作方式会在以后的博文当中介绍到。这里我们就按照官方文档,进行一次实验性的升级。 主要的升级步骤会有以下几步:
- 确保主从同步
- 在master上配置read_only,保证没有新数据写入
- 修改master上的my.cnf,并重启服务
- 修改slave上的my.cnf,并重启服务
- 在slave上执行change master to并带上master_auto_position=1启用基于GTID的复制
由于是实验环境,read_only和服务重启并无大碍。只要按照官方的GTID搭建建议做就能顺利完成升级,这里就不赘述详细过程了。下面列举了一些在升级过程中容易遇到的错误。
常见错误
gtid_mode=ON,log_slave_updates,enforce_gtid_consistency这三个参数一定要同时在my.cnf中配置。否则在mysql.err中会出现如下的报错
2015-02-26 17:11:08 32147 [ERROR] --gtid-mode=ON or UPGRADE_STEP_1 or UPGRADE_STEP_2 requires --log-bin and --log-slave-updates
2015-02-26 17:13:53 32570 [ERROR] --gtid-mode=ON or UPGRADE_STEP_1 requires --enforce-gtid-consistency
change master to 后的warnings
在按照文档的操作change master to后,会发现有两个warnings。其实是两个安全性警告,不影响正常的同步(有兴趣的读者可以看下关于该warning的具体介绍。warning的具体内容如下:
slave1 [localhost] {msandbox} ((none)) > stop slave; Query OK, 0 rows affected (0.03 sec) slave1 [localhost] {msandbox} ((none)) > change master to master_host='127.0.0.1',master_port =21288,master_user='rsandbox',master_password='rsandbox',master_auto_position=1; Query OK, 0 rows affected, 2 warnings (0.04 sec) slave1 [localhost] {msandbox} ((none)) > show warnings; +-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Level | Code | Message | +-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Note | 1759 | Sending passwords in plain text without SSL/TLS is extremely insecure. | | Note | 1760 | Storing MySQL user name or password information in the master info repository is not secure and is therefore not recommended. Please consider using the USER and PASSWORD connection options for START SLAVE; see the 'START SLAVE Syntax' in the MySQL Manual for more information. | +-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 2 rows in set (0.00 sec)
实验一:如果slave所需要事务对应的GTID在master上已经被purge了
根据show global variables like '%gtid%'的命令结果我们可以看到,和GTID相关的变量中有一个gtid_purged。从字面意思以及 官方文档可以知道该变量中记录的是本机上已经执行过,但是已经被purge binary logs to命令清理的gtid_set。 本节中我们就要试验下,如果master上把某些slave还没有fetch到的gtid event purge后会有什么样的结果。
以下指令在master上执行
master [localhost] {msandbox} (test) > show global variables like '%gtid%'; +---------------------------------+----------------------------------------+ | Variable_name | Value | +---------------------------------+----------------------------------------+ | binlog_gtid_simple_recovery | OFF | | enforce_gtid_consistency | ON | | gtid_executed | 24024e52-bd95-11e4-9c6d-926853670d0b:1 | | gtid_mode | ON | | gtid_owned | | | gtid_purged | | | simplified_binlog_gtid_recovery | OFF | +---------------------------------+----------------------------------------+ 7 rows in set (0.01 sec) master [localhost] {msandbox} (test) > flush logs;create table gtid_test2 (ID int) engine=innodb; Query OK, 0 rows affected (0.04 sec) Query OK, 0 rows affected (0.02 sec) master [localhost] {msandbox} (test) > flush logs;create table gtid_test3 (ID int) engine=innodb; Query OK, 0 rows affected (0.04 sec) Query OK, 0 rows affected (0.04 sec) master [localhost] {msandbox} (test) > show master status; +------------------+----------+--------------+------------------+------------------------------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+------------------------------------------+ | mysql-bin.000005 | 359 | | | 24024e52-bd95-11e4-9c6d-926853670d0b:1-3 | +------------------+----------+--------------+------------------+------------------------------------------+ 1 row in set (0.00 sec) master [localhost] {msandbox} (test) > purge binary logs to 'mysql-bin.000004'; Query OK, 0 rows affected (0.03 sec) master [localhost] {msandbox} (test) > show global variables like '%gtid%'; +---------------------------------+------------------------------------------+ | Variable_name | Value | +---------------------------------+------------------------------------------+ | binlog_gtid_simple_recovery | OFF | | enforce_gtid_consistency | ON | | gtid_executed | 24024e52-bd95-11e4-9c6d-926853670d0b:1-3 | | gtid_mode | ON | | gtid_owned | | | gtid_purged | 24024e52-bd95-11e4-9c6d-926853670d0b:1 | | simplified_binlog_gtid_recovery | OFF | +---------------------------------+------------------------------------------+ 7 rows in set (0.00 sec)
在slave2上重新做一次主从,以下命令在slave2上执行
slave2 [localhost] {msandbox} ((none)) > change master to master_host='127.0.0.1',master_port =21288,master_user='rsandbox',master_password='rsandbox',master_auto_position=1; Query OK, 0 rows affected, 2 warnings (0.04 sec) slave2 [localhost] {msandbox} ((none)) > start slave; Query OK, 0 rows affected (0.01 sec) slave2 [localhost] {msandbox} ((none)) > show slave status\G *************************** 1. row *************************** ...... Slave_IO_Running: No Slave_SQL_Running: Yes ...... Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 0 Relay_Log_Space: 151 ...... Last_IO_Errno: 1236 Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.' Last_SQL_Errno: 0 Last_SQL_Error: ...... Auto_Position: 1 1 row in set (0.00 sec)
实验二:忽略purged的部分,强行同步
那么实际生产应用当中,偶尔会遇到这样的情况:某个slave从备份恢复后(或者load data infile)后,DBA可以人为保证该slave数据和master一致;或者即使不一致,这些差异也不会导致今后的主从异常(例如:所有master上只有insert没有update)。这样的前提下,我们又想使slave通过replication从master进行数据复制。此时我们就需要跳过master已经被purge的部分,那么实际该如何操作呢? 我们还是以实验一的情况为例:
先确认master上已经purge的部分。从下面的命令结果可以知道master上已经缺失24024e52-bd95-11e4-9c6d-926853670d0b:1这一条事务的相关日志
master [localhost] {msandbox} (test) > show global variables like '%gtid%'; +---------------------------------+------------------------------------------+ | Variable_name | Value | +---------------------------------+------------------------------------------+ | binlog_gtid_simple_recovery | OFF | | enforce_gtid_consistency | ON | | gtid_executed | 24024e52-bd95-11e4-9c6d-926853670d0b:1-3 | | gtid_mode | ON | | gtid_owned | | | gtid_purged | 24024e52-bd95-11e4-9c6d-926853670d0b:1 | | simplified_binlog_gtid_recovery | OFF | +---------------------------------+------------------------------------------+ 7 rows in set (0.00 sec)
在slave上通过set global gtid_purged='xxxx'的方式,跳过已经purge的部分
slave2 [localhost] {msandbox} ((none)) > stop slave; Query OK, 0 rows affected (0.04 sec) slave2 [localhost] {msandbox} ((none)) > set global gtid_purged = '24024e52-bd95-11e4-9c6d-926853670d0b:1'; Query OK, 0 rows affected (0.05 sec) slave2 [localhost] {msandbox} ((none)) > start slave; Query OK, 0 rows affected (0.01 sec) slave2 [localhost] {msandbox} ((none)) > show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event ...... Master_Log_File: mysql-bin.000005 Read_Master_Log_Pos: 359 Relay_Log_File: mysql_sandbox21290-relay-bin.000004 Relay_Log_Pos: 569 Relay_Master_Log_File: mysql-bin.000005 Slave_IO_Running: Yes Slave_SQL_Running: Yes ...... Exec_Master_Log_Pos: 359 Relay_Log_Space: 873 ...... Master_Server_Id: 1 Master_UUID: 24024e52-bd95-11e4-9c6d-926853670d0b Master_Info_File: /data/mysql/rsandbox_mysql-5_6_23/node2/data/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it ...... Retrieved_Gtid_Set: 24024e52-bd95-11e4-9c6d-926853670d0b:2-3 Executed_Gtid_Set: 24024e52-bd95-11e4-9c6d-926853670d0b:1-3 Auto_Position: 1 1 row in set (0.00 sec)
可以看到此时slave已经可以正常同步,并补齐了24024e52-bd95-11e4-9c6d-926853670d0b:2-3范围的binlog日志。
MySQL5.7杀手级新特性:GTID原理与实战
一、理论篇
1.1 GTID是什么(what)
1.1.1 GTID组成和架构
- GTID 架构
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)
1.1.2 GTID和Binlog的关系
- GTID在binlog中的结构
- GTID event 结构
-
Previous_gtid_log_event
- 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之间的关系是怎么对应的呢
如何才能找到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个步骤,直到找到为止
1.1.3 重要参数的持久化
- GTID相关参数
参数 | 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
1.1.4 开启GTID的必备条件
- MySQL 5.6
ON(必选)
log_bin=ON(必选) log-slave-updates=ON(必选)
enforce-gtid-consistency(必选)
- MySQL 5.7 > MySQL5.7.13 or higher
ON(必选)
enforce-gtid-consistency(必选)
log_bin=ON(可选)--高可用切换,最好设置ON log-slave-updates=ON(可选)--高可用切换,最好设置ON
1.1.5 新的复制协议 COM_BINLOG_DUMP_GTID
- Slave sends to master range of identifiers of executed transactions to master
- Master send all other transactions to slave
- 同样的GTID不能被执行两次,如果有同样的GTID,会自动被skip掉。
slave1 : 将自身的UUID1:1 发送给 master,然后接收到了 UUID1:2,UUID1:3 event
slave2 : 将自身的UUID1:1,UUID1:2 发送给 master,然后接收到了UUID1:3 event
1.1.6 GTID重要函数和新语法
- 重要函数
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][,channel]) | 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是最后一个提交的事务。
1.2 GTID有什么好处(why)
1.2.1 classic replication [运维之痛]
1.2.2 GTID replication [so easy]
1.3 GTID的Limitation
- 不安全的事务 > 设置enforce-gtid-consistency=ON
CREATE TABLE ... SELECT statements 2. CREATE TEMPORARY TABLE or DROP TEMPORARY TABLE statements inside transactions 3. 同时更新 事务引擎 和 非事务引擎。
1.4 MySQL5.7 GTID crash-safe
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
二、实战篇(how)
2.1 使用GTID搭建Replication
2.1.1 从0开始搭建
- step 1: 让所有server处于同一个点
mysql> SET @@global.read_only = ON;
- step 2: 关闭所有MySQL
shell> mysqladmin -uusername -p shutdown
- step 3: 重启所有MySQL,并开启GTID
shell> mysqld --gtid-mode=ON --log-bin --enforce-gtid-consistency &
当然,在my.cnf中配置好最佳
- step 4: change master
mysql> CHANGE MASTER TO > MASTER_HOST = host, > MASTER_PORT = port, > MASTER_USER = user, > MASTER_PASSWORD = password, > MASTER_AUTO_POSITION = 1;
START SLAVE;
- step 5: 让master 可读可写
mysql> SET @@global.read_only = OFF;
2.1.2 从备份中恢复&搭建
- step 1: 备份
or 冷备份 --获取并且记录gtid_executed值,这个就相当于mysqldump中得到的gtid_purged
- step 2: 在新服务器上reset master,导入备份
reset master; --清空gtid信息 导入备份; --如果是逻辑导入,请设置sql_log_bin=off set global gtid_purged=xx;
- step 3: change master
mysql> CHANGE MASTER TO > MASTER_HOST = host, > MASTER_PORT = port, > MASTER_USER = user, > MASTER_PASSWORD = password, > MASTER_AUTO_POSITION = 1;
START SLAVE;
2.2 如何从classic replication 升级成 GTID replication
2.2.1 offline 方式升级
offline 的方式升级最简单。全部关机,然后配置好GTID,重启,change master to MASTER_AUTO_POSITION=1。
2.2.2 online 方式升级
这里先介绍几个重要GTID_MODE的value
- GTID_MODE = OFF : 不产生Normal_GTID,只接受来自master的ANONYMOUS_GTID
- GTID_MODE = OFF_PERMISSIVE : 不产生Normal_GTID,可以接受来自master的ANONYMOUS_GTID & Normal_GTID
- GTID_MODE = ON_PERMISSIVE : 产生Normal_GTID,可以接受来自master的ANONYMOUS_GTID & Normal_GTID
-
GTID_MODE = ON : 产生Normal_GTID,只接受来自master的Normal_GTID
-
master和slave的gtid_mode 组合搭配矩阵图
水平的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模式。
- step 1: 每台server执行 > 检查错误日志,直到没有错误出现,才能进行下一步
SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = WARN;
- step 2: 每台server执行
SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = ON;
- step 3: 每台server执行 > 不用关心一组复制集群的server的执行顺序,只需要保证每个Server都执行了,才能进行下一步
SET @@GLOBAL.GTID_MODE = OFF_PERMISSIVE;
- step 4: 每台server执行 > 不用关心一组复制集群的server的执行顺序,只需要保证每个Server都执行了,才能进行下一步
SET @@GLOBAL.GTID_MODE = ON_PERMISSIVE;
- step 5: 在每台server上执行,如果ONGOING_ANONYMOUS_TRANSACTION_COUNT=0就可以 > 不需要一直为0,只要出现过0一次,就ok
SHOW STATUS LIKE 'ONGOING_ANONYMOUS_TRANSACTION_COUNT';
- step 6: 确保所有anonymous事务传递到slave上了
SHOW MASTER STATUS;
2. 每个slave SELECT MASTER_POS_WAIT(file, position);
或者,等一段时间,只要不是大的延迟,一般都没问题
- step 7: 每台Server上执行
SET @@GLOBAL.GTID_MODE = ON;
- step 8: 在每台server上将my.cnf中添加好gtid配置
ON(必选)
enforce-gtid-consistency(必选)
log_bin=ON(可选)--高可用切换,最好设置ON log-slave-updates=ON(可选)--高可用切换,最好设置ON
- step 9: change master
STOP SLAVE; CHANGE MASTER TO MASTER_AUTO_POSITION = 1; START SLAVE;
2.3 GTID failover
2.3.1 MySQL crash
配置好loss-less semi-sync replication,可以更可靠的保证数据零丢失。
以下说的都是crash 后,起不来的情况
- binlog 在master还有日志没有传递到 slave
change master to maseter_auto_position同步好 2. mysqlbinlog 将没传递过来的binlog在新master上replay 3. 打开新master的surper_read_only=off;
- binlog 已经传递到slave
change master to maseter_auto_position同步好 2. 打开新master的surper_read_only=off;
2.3.2 OS crash
change master to maseter_auto_position同步好 2. 打开新master的surper_read_only=off;
以上操作,在传统模式复制下,只能通过MHA来实现,MHA比较复杂。
现在,在GTID模式下,实现起来非常简单,且非常方便。
2.4 GTID 运维和错误处理
- 使用GTID后,对原来传统的运维有不同之处了,需要调整过来。
- 使用Row模式且复制配置正确的情况下,基本上很少发现有复制出错的情况。
- slave 设置 super_read_only=on
2.4.1 错误场景: Errant transaction
出现这种问题基本有两种情况
1. 复制参数没有配置正确,当slave crash后,会出现重复键问题
2. DBA操作不正确,不小心在slave上执行了事务
对于第一个重复键问题
- 传统模式
* skip transation; SQL> SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
SQL> START SLAVE;
- GTID模式
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后,有可能会丢失事务
这里说下inject empty transction的隐患
- 当slave上inject empty transction,说明有一个master的事务被忽略了(这里假设是 $uuid:100)
- 事务丢失一:如果此时此刻master挂了,这个slave被选举为新master,那么其他的slave如果还没有执行到$uuid:100,就会丢失掉$uuid:100这个事务。
- 事务丢失二:如果从备份中重新搭建一个slave,需要重新执行之前的所有事务,而此时,master挂了, 又回到了事务丢失一的场景。
三、QA
3.1 如何重置gtid_executed,gtid_purged。
- 设置gtid_executed
master
- 设置gtid_purged
* 当gtid_executed 非空的时候,不能设置gtid_purged * 当gtid_executed 为空的时候(即刚刚备份好的镜像,刚搭建的mysql),可以直接SET @@GLOBAL.GTID_PURGED='0ad6eae9-2d66-11e6-864f-ecf4bbf1f42c:1-3';
3.2 如果auto.cnf 被删掉了,对于GTID的复制会有什么影响?
server-uuid 会变
3.3 手动设置 set @@gtid_purged = xx:yy, mysql会去主动修改binlog的头么
不会
3.4 GTID和复制过滤规则之间如何协同工作?MySQL,test还能愉快的过滤掉吗?
可以,改过滤的会自己过滤,不用担心
About Me
.............................................................................................................................................
● 本文整理自网络
.............................................................................................................................................
● QQ群:230161599 微信群:私聊
● 联系我请加QQ好友(646634621),注明添加缘由
● 于 2017-07-01 09:00 ~ 2017-07-31 22:00 在魔都完成
● 文章内容来源于小麦苗的学习笔记,部分整理自网络,若有侵权或不当之处还请谅解
● 版权所有,欢迎分享本文,转载请保留出处
.............................................................................................................................................
.............................................................................................................................................
使用微信客户端扫描下面的二维码来关注小麦苗的微信公众号(xiaomaimiaolhr)及QQ群(DBA宝典),学习最实用的数据库技术。
小麦苗的微信公众号 小麦苗的QQ群 小麦苗的微店
.............................................................................................................................................
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/26736162/viewspace-2142792/,如需转载,请注明出处,否则将追究法律责任。