TID代表了该实例上已经提交的事务数量巴黎人手
分类:巴黎人-数据库

背景:MySQL5.6.40,库比较小,row+gtid复制环境,但由于以前种种原因,备份还原在从库后,开启复制存在大量1062,1032错误,gtid卡在靠前位置。做复制的时候没有任何从库,每小时的备份也被运维停了。

要讨论如何恢复从库,我们得先来了解如下一些概念:

与MySQL传统复制相比,GTID有哪些独特的复制姿势?

首先看一下什么是GTID:

前言

以前从来没遇到过这种情况,相对测试环境正式环境比较复杂,而且猜测可能是之前备份还原从来没用过备份一致性参数导致,并且发现错误也没有手工检查(这个问题还在研究中,有遇到并知道原因的小伙伴欢迎指导)。

GTID_EXECUTED:它是一组包含已经记录在二进制日志文件中的事务集合

GTID(Global Transaction ID)是对于一个已提交事务的编号,并且是一个全局唯一的编号。

GTID(Global Transaction ID)是MySQL5.6引入的功能,可以在集群全局范围标识事务,用于取代过去通过binlog文件偏移量定位复制位置的传统方式。借助GTID,在发生主备切换的情况下,MySQL的其它Slave可以自动在新主上找到正确的复制位置,这大大简化了复杂复制拓扑下集群的维护,也减少了人为设置复制位置发生误操作的风险。另外,基于GTID的复制可以忽略已经执行过的事务,减少了数据发生不一致的风险。

为了今后避免因为恢复不及时导致的数据丢失,特别总结本次故障过程和大家讨论、分享。

GTID_PURGED:它是一组包含已经从二进制日志删除掉的事务集合。

陈华军,苏宁云商IT总部资深技术经理,从事数据库服务相关的开发和维护工作,之前曾长期从事富士通关系数据库的开发,PostgreSQL中国用户会核心成员,熟悉PostgreSQL和MySQL。

GTID实际上是由UUID+TID组成的。其中UUID是一个MySQL实例的唯一标识。TID代表了该实例上已经提交的事务数量,并且随着事务提交单调递增。根据GTID可以知道事务最初是在哪个实例上提交的,而且方便故障切换。

GTID虽好,要想运用自如还需充分了解其原理与特性,特别要注意与传统的基于binlog文件偏移量复制方式不一样的地方。 本文概述了关于GTID的几个常见问题,希望能对理解和使用基于GTID的复制有所帮助。

简化时间轴如下图:

 

 

 

GTID长什么样

开始---->备份主库---->恢复从库---->复制error1032,1062---->删除从库再次恢复---->复制error1032,1062---->reset master从库、主库---->准备删除从库---->误操作删主库----->恢复主库----->跳过大量1062、1032错误---->找drop db位置恢复从库---->对比主从数据---->手工补数据---->结束

 

 

接下来就看一下怎么在GTID模式下快速的添加一个slave:

根据官方文档定义,GTID由source_id加transaction_id构成。

下面按照我的记忆描述下当时的场景:

在继续讨论时,我们先来看下如何新建一个基于GTID的slave。

[MySQL 5.6] GTID实现、运维变化及存在的bug

我们知道在没有GTID复制以前,MySQL的复制是基于binary log和position来做的,之前的复制我们要执行下面的change语句:

GTID = source_id:transaction_id

一、首次备份主库、搭建从库

第一次搭建从库,从主库的备份未使用master-data=2 single-transaction(保证事务备份时的一致性)参数迁移后,报大量1062和1032错误(家家有本难念的经,不多说了)

 

巴黎人手机版 1

通过了解上面的两个参数,我们现在只需要:

CHANGE MASTER TO MASTER_HOST='',MASTER_PORT=3306,MASTER_USER='repl',MASTER_PASSWORD='*****',MASTER_LOG_FILE='mysqlbinlog.000003',MASTER_LOG_POS=99721204;

上面的source_id指示发起事务的MySQL实例,值为该实例的server_uuid。server_uuid由MySQL在第一次启动时自动生成并被持久化到auto.cnf文件里,transaction_id是MySQL实例上执行的事务序号,从1开始递增。 例如:

二、第二次还原主库到从库

于是第二次重新导入。

同样报错。在导入从库前使用reset master;将从库binlog清除。

由于操作人员不了解reset master含义及执行结果,又在主库做了reset master;

结果导致主库所有binlog日志被清除并且binlog position置为1;

这里贴以下官方说明,别没事干就在主库上用这条。

 

巴黎人手机版 2

再次导入发现依旧大量报1032,1062错误。

由于怀疑是因为备份时没使用--single-transaction参数,准备删除从库,加参数重新备份主库。

1.从主库上做一个备份时记录备份时gtid_executed的值。

 

 

e6954592-8dba-11e6-af0e-fa163e1cf111:1

三、误删除主库

结果误操作删除主库(这个锅一部分原因要甩给mysql naivcat这个工具,垂直排列库,稍微不注意就容易点错。还是建议大家听吴老师的用官方的workbench),删库还是两人校对,在操作系统上执行,删前没把握最好备份一遍。

删库这种操作谨慎谨慎再谨慎,重要的事情说三遍!

删库这种操作谨慎谨慎再谨慎,重要的事情说三遍!

删库这种操作谨慎谨慎再谨慎,重要的事情说三遍!

drop database;(在naivcat上右键删除库,但binlog日志中还是会记录DROP DATABASE这条记录)

这时候为了保证业务不中断,立马在主库上通过之前的备份文件恢复了一套库,当然数据肯定丢失了,但可以推算丢失数据的时间段(从备份完毕开始--->DROP DATABASE)。

PS.请不要问我为什么删库,为什么删完又恢复了一套库,因为都不是我干的。。。。。。

万幸的是误删除主库但并未删除从库,而且从库的io_thread仍然处于yes状态(回顾吴老师的课程,也就是说虽然库被删除了但其实删库前的数据=备份数据+io_thread已下载的删除主库前的数据),由于sql_thread仍然停到gtid靠前的位置

 

巴黎人手机版 3

2.在新的slave上恢复此备份时设置从库的gtid_purged的值为备份时master上gtid_executed的值。

适当减小binlog文件的大小
如果开启GTID,理论上最好调小每个binlog文件的最大值,以缩小扫描文件的时间。

而我们在GTID就可以执行以下的change语句:

一组连续的事务可以用'-'连接的事务序号范围表示。例如

四、跳过大量1032,1062错误

这个时候只要看下备份文件的gtid位置,并purge到该位置(之前备份丢了,随便找了一个备份的截图,理解万岁)。

##这里说明一下为什么直接purge到备份的结尾位置,因为书库备份的数据中1032和1062错误太多,且主库已经删除没办法通过脚本对比跳过大量1032,1062错误(吴老师友情提供),在能够保证是从主库逻辑备份过来的情况下(主从数据一致),我们选择快速跳过大量错误(偷懒加情况急),直接purge到备份最后的位置。

 

巴黎人手机版 4

##上图是随便截的一个备份文件最开头的位置,请忽略那个gtid的值,意思明白就行。

set @@gtid_purged='fb1f83af-1915-11e8-811b-000c29c4d77d:1-500';

注:‘500’代表备份文件最后一个执行的事务的gtid。gtid_purged代表数据库已经在从库上重放过1-500这段事务。

 

 

CHANGE MASTER TO  MASTER_HOST='****', MASTER_USER='repl',  MASTER_PASSWORD='******',  MASTER_PORT=3306,  master_auto_position=1;

e6954592-8dba-11e6-af0e-fa163e1cf111:1-5

五、找到主库DROP DATABASE的GTID位置

purge到该位置然后再确定drop database的位置上(思路:如果不确定dropdatabase的位置就start slave 那么从库会应用主库的binlog也就会执行主库drop database的操作,为了避免从库重放主库drop database的操作,我们要设法让gtid在从库停到drop database前一个gtid的位置)

注:可以通过大致删库时间或者从从库的show slave statusG上看到主库的binlog位置从后往前找DROP DATABASE的位置,如果删库后做了reset master那就只能从从库的relay-bin-log上找了(切记主库没事别reset master);

mysqlbinlog    -vvv  --base64-output=decode-rows  relay-bin.000017

 

巴黎人手机版 5

通过mysqldump可以完成我们需要的功能。

GTID(Global Transaction ID)是MySQL5.6引入的功能,可以在集群全局范围标识事务,用于取代过去通过binlog文件偏移量定位复制位置的传统方式。借助GTID,在发生主备切换的情况下,MySQL的其它Slave可以自动在新主上找到正确的复制位置,这大大简化了复杂复制拓扑下集群的维护,也减少了人为设置复制位置发生误操作的风险。另外,基于GTID的复制可以忽略已经执行过的事务,减少了数据发生不一致的风险。

 

更一般的情况是GTID的集合。GTID集合可以包含来自多个source_id的事务,它们之间用逗号分隔;如果来自同一source_id的事务序号有多个范围区间,各组范围之间用冒号分隔,例如:

六、启动从库SQL_THREAD

在从库上执行start slave sql_thread until的命令,这里需要说明,因为主库已经还原,业务跑起来了,这时候开启io_thread没有什么意义,所以只用让从库的sql_thread线程重放DROP DATABASE之前的事务就行。

root@localhost[{none}]>start slave sql_thread until sql_before_gtid='fb1f83af-1915-11e8-811b-000c29c4d77d:2343';

启动slave,并且让从库gtid停在主库drop database操作之前一个gtid就可以,再还原到主库就能立马投入使用,还不会导致数据丢失。

 

巴黎人手机版 6

确保从库executed_gtid_set到了我们before的前一个值就可以备份了,然后dump这份数据还原主库,当然如果从库性能不错的话可以考虑应用端更改连接,这样速度更快一些。

但比较麻烦的就是,要保证生产的实时性,删库后立即在主库上还原了之前用来恢复从库的备份文件,这就肯定会导致中间数据丢失。

 

GTID虽好,要想运用自如还需充分了解其原理与特性,特别要注意与传统的基于binlog文件偏移量复制方式不一样的地方。本文概述了关于GTID的几个常见问题,希望能对理解和使用基于GTID的复制有所帮助。

我们可以看到,基本上来说指定复制的时候原来的binary log方式需要指定MASTER_LOG_FILE和MASTER_LOG_POS,而GTID复制却不需要知道这些参数。

e6954592-8dba-11e6-af0e-fa163e1cf111:1-5:11-18,

七、数据对比还原

这时候只能使用用之前用来搭建从库的备份再恢复一个库,再用pt-table-checksum对比主库和恢复库,从库和恢复库不一致的数据,用pt-table-sync生成对应语句。然后手工把数据补进系统中。

对比1:主库:备份数据还原的库---->目标:找到主库在删库之后应用又写入了哪些数据。

对比2:从库:备份数据还原的库---->目标:找到备份数据之后,删库之前应用在主库里写了哪些数据。

因为量不是很大,手工对比一下就行,当然数据还原的坑也有很多,不过基本上都被研发填了。

 

GTID长什么样

下面看一下怎么在GTID的模式下创建主从复制:

e6954592-8dba-11e6-af0e-fa163e1cf3f2:1-27

总结:

头一回碰到删库情况还是有点蒙,还好主库用的是GTID找binlog日志中的位置相对容易一点。这次恢复最幸运的就是还好从库卡在靠前的位置,要不然即使有了从库,数据也会被删了,恢复起来相对更麻烦些。

对于gtid的恢复,课上吴炳锡老师都讲过,但是一上手还是慢了几拍,还是要通过实战多练习加深手感避免在真实情况下懵逼。

最后特别鸣谢:知数堂叶金荣老师和吴炳锡老师在故障发生时给予的帮助和支持。

转载请注明出处

目前主库上的状态(3301):

根据官方文档定义,GTID由source_id加transaction_id构成。
GTID = source_id:transaction_id

从上面可以看得到,在GTID的模式下我们不再需要知道MASTER_LOG_FILE和MASTER_LOG_POS两个参数,相比之下我们只需要指定master就可以了,这对于创建复制来说简单的多了。在GTID的模式下我们需要知道以下两个全局变量:

即,GTID集合拥有如下的形式定义:

巴黎人手机版 7

上面的source_id指示发起事务的MySQL实例,值为该实例的server_uuidserver_uuid由MySQL在第一次启动时自动生成并被持久化到auto.cnf文件里,transaction_id是MySQL实例上执行的事务序号,从1开始递增。 例如:
e6954592-8dba-11e6-af0e-fa163e1cf111:1

root@perconatest09:23:44>show global variables like 'GTID_%'G
*************************** 1. row ***************************
Variable_name: gtid_executed
Value: 5031589f-3551-11e7-89a0-00505693235d:1-12,
806ede0c-357e-11e7-9719-00505693235d:1-11,
a38c33ee-34b7-11e7-ae1d-005056931959:1-24
*************************** 2. row ***************************
Variable_name: gtid_executed_compression_period
Value: 1000
*************************** 3. row ***************************
Variable_name: gtid_mode
Value: ON
*************************** 4. row ***************************
Variable_name: gtid_owned
Value:
*************************** 5. row ***************************
Variable_name: gtid_purged
Value: 5031589f-3551-11e7-89a0-00505693235d:1-12,
806ede0c-357e-11e7-9719-00505693235d:1-11,
a38c33ee-34b7-11e7-ae1d-005056931959:1-12

gtid_set:

[zejin] 3301>show global variables like 'gtid_executed';
+---------------+-------------------------------------------+
| Variable_name | Value |
+---------------+-------------------------------------------+
| gtid_executed | a97983fc-5a29-11e6-9d28-000c29d4dc3f:1-15 |
+---------------+-------------------------------------------+
1 row in set (0.00 sec)

[zejin] 3301>show global variables like 'gtid_purged';
+---------------+-------------------------------------------+
| Variable_name | Value |
+---------------+-------------------------------------------+
| gtid_purged | a97983fc-5a29-11e6-9d28-000c29d4dc3f:1-13 |
+---------------+-------------------------------------------+
1 row in set (0.00 sec)

一组连续的事务可以用'-'连接的事务序号范围表示。例如
e6954592-8dba-11e6-af0e-fa163e1cf111:1-5

 

uuid_set [, uuid_set] ...

巴黎人手机版 8

更一般的情况是GTID的集合。GTID集合可以包含来自多个source_id的事务,它们之间用逗号分隔;如果来自同一source_id的事务序号有多个范围区间,各组范围之间用冒号分隔,例如:
e6954592-8dba-11e6-af0e-fa163e1cf111:1-5:11-18,
e6954592-8dba-11e6-af0e-fa163e1cf3f2:1-27

我们主要需要看到的就是gtid_executed和gtid_purged两个参数,

| ''

 

即,GTID集合拥有如下的形式定义:
gtid_set:
    uuid_set [, uuid_set] ...
    | ''

gtid_executed:这个是已经执行过的所有的事物的GTID的一个系列串,也就是binary log里面已经落盘的事物的序列号。这个参数是只读的,不能够进行设置。

uuid_set:

 

uuid_set:
    uuid:interval[:interval]...

gtid_purged:这个序列是指我们在binary log删除的事物的GTID的序列号。我们可以手动进行设置,方便我们做一些管理。

uuid:interval[:interval]...

 

uuid:
    hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh

这两个参数理解以后,接下来我们看一下怎样去添加一个GTID复制的从库:

uuid:

step1:用mysqldump做一个全备

h:
    [0-9|A-F]

(1):从主库做一个全备份,而且要记录主库备份时间点的gtid_executed

hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh

mysqldump --all-databases --single-transaction --triggers --routines --events --host=127.0.0.1 --port=3301 --user=root --password=123 > dump3301.sql

interval:
    n[-n]

(2):从库进行恢复,而且将从库的gtid_purged设置为我们第一步获取的master的gtid_executed

h:

本文由巴黎人手机版发布于巴黎人-数据库,转载请注明出处:TID代表了该实例上已经提交的事务数量巴黎人手

上一篇:做如下修改,先简单介绍一下这个新手卡录入后 下一篇:没有了
猜你喜欢
热门排行
精彩图文