
SET GLOBAL ENFORCE_GTID_CONSISTENCY='WARN'
SET GLOBAL ENFORCE_GTID_CONSISTENCY='ON'
SET GLOBAL GTID_MODE = 'OFF_PERMISSIVE'
SET GLOBAL GTID_MODE = 'ON_PERMISSIVE'
SET GLOBAL GTID_MODE = 'ON'
配置文件中GTID_MODE = ON
ENFORCE_GTID_CONSISTENCT
平滑关闭步骤:
(1):stop slave(如果是主库就不必执行此步骤)
(2):SET GLOBAL GTID_MODE = 'ON_PERMISSIVE'
(3):SET GLOBAL GTID_MODE = 'OFF_PERMISSIVE'
(4):SET GLOBAL GTID_MODE = 'OFF'
之后查看状态:
select @@GLOBAL.GTID_MODE
配置文件中GTID_MODE = OFF
关闭ENFORCE_GTID_CONSISTENCY:
在线修改 :SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = off
配置文件中 :ENFORCE_GTID_CONSISTENCY = off
传统主从复制的binlog和position号选择切换时间的第一个binlog的第一号
在 Mysql 5.6 之前版本中 , 如果要修改一个表的ddl信息 ,需要锁表 。
具体步骤如下:
下面是Mysql官方文档对于DDL *** 作的总结:
http://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-overview.html
http://dev.mysql.com/doc/refman/5.7/en/innodb-create-index-overview.html
可以使用 Alter 语句支持 DDL 特性 ,比如可以用 LOCK = NONE 无锁变更。
percona是一个开源产品 , 是管理Mysql的工具。
PT-OSC(Percona Toolkit Online Schema Change)
https://www.percona.com/doc/percona-toolkit/3.0/pt-online-schema-change.html
Percona Toolkit 包含很多 mysql 管理的功能 ,现在要说的是 online-schema-change上
PT-OSC 原理是建表 ,使用触发器同步数据 ,然后原子性rename。
这样可以支持在线无锁,不停机Online-DDL 。
具体步骤如下:
Percona 有一些限制和缺陷 ,根据它的原理 ,原表不能存在触发器 ,这玩意是唯一。另外原表必须存在PK或者UK。另外就是触发器的问题了,触发器带来性能开销,并且无法停止,那我就不能控制我同步的开关和速度。
但是gh-ost说它可以。
https://github.com/github/gh-ost
go-ost基于bin-log同步 , 基于binlog肯定都是伪装成一个replica。
由于使用单线程回放binlog来替换触发器,所以增量DML回放效率不如触发器,因为pt-osc的增量回放并发度是与业务DML并发度相同的,是多线程的。
相对于percona的优势是:
因为出的太晚了 ,然后percona 和 gh-ost等等开源产品已经大规模实践了,Mysql就更加没什么实践案例和经验了,大家就不太愿意尝试或者迁移了。
大厂来说基本上都是平台封装了,类似idb ,会把无锁变更细节屏蔽了,只需要提工单就可以了 ,但是底层基本上也是建表同步rename个思路。
小公司的话,可以使用percona 、 go-ost 等工具。
MySQL 8.0 Online DDL和pt-osc、gh-ost深度对比分析
Mysql Online DDL
pt-online-schema-change
gh-ost
MySQL5.6在线表结构变更(online ddl)总结
首先要说明pt-online-schema-change工具并不是说修改表结构的时候不上锁,通常我们说的锁一般包含innodb 行锁和MDL lock。而pt-online-schema-change工具就是将某些使用COPY算法的DDL *** 作使用DML *** 作来代替,换句话说就是使用Innodb row锁来代替MDL lock,因为MySQL原生的COPY算法的DDL会在MDL lock SNW这个类型保护下完整个表复制 *** 作,整个复制过程中是不允许DML *** 作,因此造成了我们COPY算法的DDL堵塞线程正常的现象,当然哪些DDL可以online进行可以参考官方文档online ddl一节。整个pt-online-schema-change工具修改过程中,只会在rename阶段才会上MDL LOCK的X锁,但是rename *** 作一般非常快速。
我们大概看一下pt-online-schema-change的工作方式,这个实际上开启genrnal log就能看出来下面是重点步骤(我的表名叫做testpt_osc):
从整个过程来讲需要注意的几个地方:
我们可以看到整个过程中有如下的重点知识点:
其次对于第4和第5点来讲,有出现死锁的可能。下面我们分别讨论。
在pt-online-schema-change中,触发器占据了重要的地位,我们需要了解一下触发器和事务之间的关系。我们常用的触发器包含了before和after触发器,代表着对原表进行DML *** 作前或者后进行其它的 *** 作,下面是我定义的两个测试的触发器如下:
显然如果对t1表进行数据插入,那么会在之前向t2表插入一条数据,然后在之后向t3插入一条数据,这一点可以通过函数调用trace进行验证如下:
这里就能够看到顺序了,其次我们还需要知道这些所有的 *** 作会包裹在一个事务里面,这一点也可以通过函数调用trace进行验证,还可以使用binlog进行验证,下面是一次调用的binlog信息:
这里我们使用binlog不仅验证了执行顺序并且还验证了所有 *** 作都包含在一个事务里面。 既然所有的语句都包裹在一个事务里面,那么加锁的范围就更大了,这不仅关系到本身的DML *** 作表,并且还关系到触发语句的相关表,需要额外注意。
其次所有语句不仅包裹在一个事务里面,并且共享一个错误返回接口,那么如下的错误:
我们惊讶的发现t1表一条数据都没有,但是居然返回重复的行。 原因就在于虽然t1表没有数据,但是t2或者t3表有违反唯一性检查的可能,因此返回了错误,错误由统一的接口返回给客户端。
最后触发器会导致处理逻辑混乱, 尽量避免使用触发器 。
关于ignore语法我们以insert ignore语法为例,一般来讲如果遇到重复行insert ignore语法会通过忽略重复值错误的方式进行跳过,这实际上和replace的处理方式一致,但是replace不同的是如果遇到重复行不是进行忽略,而是执行的delete然后执行insert *** 作。换句话说他们的触发形式一致,但是触发后执行的行为是不同的,下面我们就来看看。
首先对于insert语句来讲我们需要定位到需要插入的位置,这部分略过。
这一步对于主键/唯一索引 而言需要判断是否已经有重复的行。其判断标准基本都是通过插入的值进行索引定位,然后判断定位游标的值是否和需要插入值相同,下面是栈帧:
如果存在重复的行,这需要进行判断了:
因为我们知道通常insert锁并不会建立显示的锁。对于如果出现了重复的行,持有重复行数据的事务并没有提交或者回滚,需要其事务完成提交或者回滚,然后再进行相应的抛错或者继续插入。需要注意的是对于replace/insert on dup 在进行唯一性检查的时候,通常加的LOCK_S锁,而其他 *** 作通常加的是 LOCK_X。
当然如果没有重复的行,那么接下来就可以继续进行insert插入 *** 作了,Insert ignore/replace实现都是进行insert *** 作。如果有重复行呢?那么接下来进行分析。
这里我们也很明白了,对于了insert ignore/replace是通过主键/唯一键进行判断是否重复行的,具体点来说就是如何处理错误HA_ERR_FOUND_DUPP_KEY。 如果表中一个能够判断唯一性的索引都没有,那么即便2条数据一模一样也不会标记为重复行,视为2条不同的数据 ,当然insert on dup 这里也是同样的逻辑。
在进行唯一性检测的时候,会先检查主键的唯一性,然后依次检查各个唯一索引的唯一性是否满足。
首先对于多行插入和insert select来讲,每次innodb层插入的行数为1行,我们应该牢牢树立以行为单位的处理流程,我们可以在函数Sql_cmd_insert::mysql_insert 中找到 一个大的while 循环,这就是处理的循环。
我们也需要明白,进行判断唯一性的时候是先判断主键的唯一性,如果满足则插入主键数据,然后依次判断二级唯一索引,如果满足则进行插入。这里涉及到一个问题,如果主键数据插入了,但是二级唯一索引由于违法唯一性那么,前面主键插入的数据是需要回滚的。再或者我们执行的insert select *** 作,其中前面的一些行不违反唯一性插入了,但是随后的某行违法了唯一性,那么前面插入的数据也是需要回滚的。函数row_insert_for_mysql_using_ins_graph 中进行这种逻辑处理。
回滚栈帧:
如果有重复的行并且产生了错误HA_ERR_FOUND_DUPP_KEY ,那么就不能进行insert *** 作了,这里就会根据不同的语法进行不同的 *** 作了。我们在函数(write_record )中可以找到这种分支处理逻辑。
实际上在处理重复行错误的时候,在内部分为了3种方式如下:
但是需要注意的是,当前版本报错后,自增值并不会回退。
再说对于普通的insert *** 作而言,影响的行数通常为1。replace/insert into on dup如果遇到了 重复行更改后 (注意不是直接插入成功的状态),通常返回影响的行数为2如下:
因此不管怎么看起来都是影响行数为2,也不要奇怪。
DML回执接口:
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)