gh-ost学习笔记
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J7hhPnvg-1641550092432)(https://github.com/WQMysqlDBA/gh-ost/blob/master/doc/images/gh-ost-logo-light-160.png?raw=true)]
"开始吧"
gh-ost github开源的一个online ddl工具
某位业内不太知名,朋友圈内比较知名的同学,关于何时使用gh-ost,做了一个经典的描述
"100万行数据一下,,可以使用online ddl
超过百万,,可以使用gh-ost"
(。。。就这么几个字,他还写个错别字)
"了解一下mysql的ddl的几种方式"
1、MySQL 5.6 InnoDB 存储引擎在线DDL功能:
优点:
添加、删除字段或索引、添加主键、修改字段名字不会锁表。
局限性:
修改列数据类型 、删除表主键、修改字符集、添加全文索引会锁表
Online ddl是一个事务操作(从库延迟会严重)、取消会造成事务回滚影响数据库性能
2、pt-online-schema-change:
1)表不能存在其他触发器,否则报错
2)触发器存在锁竞争问题,对MySQL的性能造成比较大的影响,严重时甚至会拖垮数据库。
3)Rename可能出各种问题:阻塞原始表业务操作过久、丢数据、切换失败等
4)大表copy 造成内存热数据溢出
5)无法暂停:当主库业务负载开始增高时,你可能会想要暂停还没完成的修改表定义的任务。可是基于触发器的方案没办法这么做,只能取消操作,删除临时表、删除触发器。
6)当数据量增多、业务压力增大之后,就会碰到了越来越多的问题,有一些操作只敢在非业务低峰期才敢执行。
3、gh-ost有以下特点:
1)轻量,无触发器,因此对原表只copy,影响小
2)可以测试(在从库执行一遍)
3)提供暂停服务(业务忙了接着暂停,注意binlog清理期限)
4)伪装成从库,流方式读取变更的binlog,异步复制原理,应用到幽灵表
好处
gh-ost 承担一些其他工具留给数据库执行的任务,无触发器。
gh-ost可以更好地控制迁移过程;
可以真正暂停它;
可以真正将迁移的写入负载与主服务器的工作负载分离。
此外,它还提供了许多可操作的特权,使其更安全、可信赖且易于使用。
(异步,都是异步,只要binlog是全的,随便停止随便应用,就是玩)
gh-ost的工作流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ulSIh5fN-1641550092434)(https://github.com/WQMysqlDBA/gh-ost/blob/master/doc/images/gh-ost-general-flow.png?raw=true)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bLNo6P6W-1641550092434)(https://github.com/WQMysqlDBA/gh-ost/blob/master/doc/images/gh-ost-operation-modes.png?raw=true)]
(深颜色表示Priamry节点,浅颜色表示Secondary节点)
gh-ost有三种工作模式
1、连接从库,在主库转换 b
2、连接主库,在主库转换 a
3、在从库上测试和转换 c
-
1、连接从库,在主库转换 (default)
这是gh-ost的默认模式 1、gh-ost 将会检查从库状态,找到集群结构中的主库并连接,接下来进行迁移操作 2、在主库上创建 _xxx_gho(和原表表结构一致)、_xxx_ghc(记录变更日志),并修改 _xxx_gho 表结构 例如: _sbtest1_ghc 变更日志,即binlog应用的日志 _sbtest1_gho 幽灵表 sbtest1 原表 3、业务正常进行,行数据在主库上读写,读取从库的二进制日志,将变更应用到主库的幽灵表上 4、在从库收集表格式,字段&索引,行数等信息 5、在从库上读取内部的变更事件(如心跳事件) 6、在主库切换表 ./gh-ost --max-load=Threads_running=20 \ --critical-load=Threads_running=200 \ --critical-load-interval-millis=5000 \ --chunk-size=10000 \ --user="root" \ --password="xxxx" \ --host='xxxxxxxxxxxx' --port=3306 \ --database="test" --table="sbtest1" \ --verbose --debug --stack \ --alter="add key idx_datetime(datetime)" \ --initially-drop-ghost-table \ --initially-drop-old-table \ --execute 2>&1 | tee rebuild_t1.log
-
2、连接主库,在主库转换
需要使用 --allow-on-master 选项: 在主库上创建 _xxx_gho、_xxx_ghc,并修改 _xxx_gho 表结构; 在主库上读源表的数据写入 _xxx_gho 表中; 从主库上读取二进制日志事件,将变更应用到主库上的 _xxx_gho 表; 在主库上完成表切换。 如果你没有从库,或者不想使用从库,你可以直接在主库上操作。 gh-ost 将会直接在主库上进行所有操作。你需要持续关注复制延迟问题。 你的主库的二进制日志必须是 RBR 格式。 在这个模式中你必须指定 --allow-on-master 参数 ./gh-ost --max-load=Threads_running=20 \ --critical-load=Threads_running=200 \ --critical-load-interval-millis=5000 \ --chunk-size=10000 \ --user="root" --password="taotao" \ --host=127.0.0.1 --port=3306 \ --database="test" --table="sbtest1" \ --verbose --debug --stack --allow-on-master \ --alter="add key idx_createtime(createtime) " --initially-drop-ghost-table --initially-drop-old-table \ --execute 2>&1 | tee rebuild_t1.log
-
3、在从库进行测试和转换
这种模式会在从库上做修改。gh-ost 仍然会连上主库,但所有操作都是在从库上做的,不会对主库产生任何影响。 在操作过程中,gh-ost 也会不时地暂停,以便从库的数据可以保持最新。gh-ost 将控制速度保证从库可以及时的进行数据同步 --migrate-on-replica 选项让 gh-ost 直接在从库上修改表。最终的切换过程也是在从库正常复制的状态下完成的。 --migrate-on-replica 表示 gh-ost 会直接在从库上进行迁移操作。即使在复制运行阶段也可以进行表的切换操作 --test-on-replica 表明操作只是为了测试目的。在进行最终的切换操作之前,复制会被停止。原始表和临时表会相互切换,再切换回来,最终相当于原始表没被动过。主从复制暂停的状态下,你可以检查和对比这两张表中的数据。 --test-on-replica 表示 迁移操作只是为了测试在切换之前复制会停止,然后会进行切换操作,然后在切换回来,你的原始表最终还是原始表。两个表都会保存下来,复制操作是停止的。你可以对这两个表进行一致性检查等测试操作。
gh-ost限制条件 违反限制条件gh-ost会报错,所以工具还是比较安全的。 1.做的过程会间隙的锁部分记录(记录数chunk-size参数定义),:因为copy数据使用了 insert ..select from ... where pk >? and pk< ? lock in share mode 2.Master-master setup is only supported in active-passive setup. Active-active (where table is being written to on both masters concurrently) is unsupported. It may be supported in the future. 这个原因估计时gh-ost代码实现使用了显式加锁的方式。 3.The two before & after tables must share a PRIMARY KEY or other UNIQUE KEY 4.Foreign keys not supported 5.Triggers are not supported.
暂停操作:
#暂停
echo throttle | socat - /tmp/gh-ost.test.t1.sock
#恢复
echo no-throttle | socat - /tmp/gh-ost.test.t1.sock
修改限速参数:
echo chunk-size=100 | socat - /tmp/gh-ost.t1.sock
echo max-lag-millis=200 | socat - /tmp/gh-ost.t1.sock
echo max-load=Thread_running=3 | socat - /tmp/gh-ost.t1.sock
2022-01-07 11:53:33 INFO starting gh-ost 1.1.2
2022-01-07 11:53:33 INFO Migrating `qdump`.`sbtest2`
2022-01-07 11:53:33 INFO inspector connection validated on 10.244.0.43:3306
2022-01-07 11:53:33 INFO User has ALL privileges
2022-01-07 11:53:33 INFO binary logs validated on 10.244.0.43:3306
2022-01-07 11:53:33 INFO Inspector initiated on gh-ost-f4d1c00-0:3306, version 5.7.26-log
2022-01-07 11:53:33 INFO Table found. Engine=InnoDB
2022-01-07 11:53:33 DEBUG Estimated number of rows via STATUS: 1000
2022-01-07 11:53:33 DEBUG Validated no foreign keys exist on table
2022-01-07 11:53:33 DEBUG Validated no triggers exist on table
2022-01-07 11:53:33 INFO Estimated number of rows via EXPLAIN: 1000
2022-01-07 11:53:33 DEBUG Potential unique keys in sbtest2: [PRIMARY (auto_increment): [id]; has nullable: false]
2022-01-07 11:53:33 INFO Recursively searching for replication master
2022-01-07 11:53:33 DEBUG Looking for master on 10.244.0.43:3306
2022-01-07 11:53:33 INFO Master found to be gh-ost-f4d1c00-0:3306
2022-01-07 11:53:33 INFO log_slave_updates validated on 10.244.0.43:3306
2022-01-07 11:53:33 INFO streamer connection validated on 10.244.0.43:3306
2022-01-07 11:53:33 DEBUG Streamer binlog coordinates: mysql-bin.000030:486171970
2022-01-07 11:53:33 INFO Connecting binlog streamer at mysql-bin.000030:486171970
[2022/01/07 11:53:33] [info] binlogsyncer.go:133 create BinlogSyncer with config {
99999 mysql 10.244.0.43 3306 gh-ost false false <nil> false UTC true 0 0s 0s 0 false}
[2022/01/07 11:53:33] [info] binlogsyncer.go:354 begin to sync binlog from position (mysql-bin.000030, 486171970)
[2022/01/07 11:53:33] [info] binlogsyncer.go:203 register slave for master server 10.244.0.43:3306
2022-01-07 11:53:33 DEBUG Beginning streaming
2022-01-07 11:53:33 INFO rotate to next log from mysql-bin.000030:0 to mysql-bin.000030
[2022/01/07 11:53:33] [info] binlogsyncer.go:723 rotate to (mysql-bin.000030, 486171970)
2022-01-07 11:53:33 INFO applier connection validated on 10.244.0.43:3306
2022-01-07 11:53:33 INFO applier connection validated on 10.244.0.43:3306
2022-01-07 11:53:33 INFO will use time_zone='+08:00' on applier
2022-01-07 11:53:33 INFO Examining table structure on applier
2022-01-07 11:53:33 INFO Applier initiated on gh-ost-f4d1c00-0:3306, version 5.7.26-log
2022-01-07 11:53:33 INFO Dropping table `qdump`.`_sbtest2_gho`
2022-01-07 11:53:33 INFO Table dropped
2022-01-07 11:53:33 INFO Dropping table `qdump`.`_sbtest2_del`
2022-01-07 11:53:33 INFO Table dropped
2022-01-07 11:53:33 INFO Dropping table `qdump`.`_sbtest2_ghc`
2022-01-07 11:53:33 INFO Table dropped
2022-01-07 11:53:33 INFO Creating changelog table `qdump`.`_sbtest2_ghc`
2022-01-07 11:53:33 INFO Changelog table created
2022-01-07 11:53:33 INFO Creating ghost table `qdump`.`_sbtest2_gho`
2022-01-07 11:53:33 INFO Ghost table created
2022-01-07 11:53:33 INFO Altering ghost table `qdump`.`_sbtest2_gho`
2022-01-07 11:53:33 DEBUG ALTER statement: alter /* gh-ost */ table `qdump`.`_sbtest2_gho` ADD COLUMN o2 varchar(10)
2022-01-07 11:53:33 INFO Ghost table altered
2022-01-07 11:53:33 INFO Altering ghost table AUTO_INCREMENT value `qdump`.`_sbtest2_gho`
2022-01-07 11:53:33 DEBUG AUTO_INCREMENT ALTER statement: alter /* gh-ost */ table `qdump`.`_sbtest2_gho` AUTO_INCREMENT=1000001
2022-01-07 11:53:34 INFO Ghost table AUTO_INCREMENT altered
2022-01-07 11:53:34 INFO Intercepted changelog state GhostTableMigrated
2022-01-07