
# gh-ost工具
#### 背景
Percona社区的pt-osc的开源DDL工具依赖于触发器来将源表的写操作映射到新表。虽然使用触发器可以提高同步的效率，但触发器执行的开销会对于主库的性能产生很大的影响。另外拷贝数据和变更数据可能处于并行状态，如果在迁移过程中对表的更新比较频繁会引入大量的锁竞争问题。
gh-ost是GitHub开源的一款在线DDL工具，相比pt-osc不依赖于触发器，而是通过模拟备库，在格式为ROW的Binlog中获取增量的变更，再异步同步到镜像表中。其将迁移的写入负载与主服务器的工作负载分离，避免了对于主库性能的影响。同时异步执行增量变更也规避了触发器导致的锁竞争问题。此外gh-ost维护了一张心跳表，用来记录DDL过程中的每个阶段，在出现异常时，可以从根据心跳日志恢复到指定位置，解决了pt-osc在运行过程中出现异常，需要从头开始的局限。
#### 流程图
图1流程图   
![](https://support.huaweicloud.com/usermanual-rds-mysql/zh-cn_image_0000002247222745.png "点击放大")
#### gh-ost三种模式架构
- 连接备库，在主库转换（默认）
  - 在主库创建和原表结构相同的_xxx_gho表，和记录变更状态的_xxx_ghc表。_xxx_ghc表用来写入Online DDL的进度以及时间。
  
  - 修改_xxx_gho表的结构。
  
  - 在主库上拷贝已有的数据到_xxx_gho。
  
  - 从备库上获取增量Binlog，完成增量数据的变更。
  
  - 在源表上加锁，确认_xxx_ghc表中的时间，保证数据同步。
  
  - 用_xxx_gho替换源表。
   
- 连接主库，在主库转换
  - 在主库创建_xxx_gho表和_xxx_ghc表。
  
  - 修改_xxx_gho表的结构。
  
  - 在主库上拷贝源表的数据到_xxx_gho。
  
  - 在主库上获取增量Binlog，完成增量数据的变更。
  
  - 在源表上加锁，确认_xxx_ghc表中的时间，保证数据同步。
  
  - 用_xxx_gho表替换源表。
   
- 在备库上测试和转换 该模式下gh-ost会简单连接到主库，但是所有的操作都是在备库上进行，不会对主库进行任何改动。
  "-migrate-on-replica"选项让 gh-ost 直接在备库上修改表。最终的切换过程也是在备库正常复制的状态下完成的。
  "-test-on-replica"表明操作只是为了测试目的。在进行最终的切换操作之前，复制会被停止。原始表和临时表会相互切换，再切换回来，最终相当于原始表没变动。主从复制暂停的状态下，可以检查和对比这两张表中的数据。
  
 
#### 使用限制
- Binlog格式必须使用row，且"binlog_row_image"的值必须是"FULL"。
- 需要用户的权限为：SUPER, REPLICATION CLIENT, REPLICATION SLAVE
  - 如果确认Binlog的格式为row，那么可以加上"-assume-rbr"，则不再需要super权限。
   
- 不支持带有外键约束的表。
- 不支持带有触发器的表。
- 执行DDL前后的表，需要有相同的主键或者有非空的唯一索引。
- 迁移表的主键或者非空唯一索引包含枚举类型时，迁移效率会大幅度降低。
 
#### 参考案例
```
gh-ost -max-load=Threads_running=20 \ 
           -critical-load=Threads_running=100 \ 
           -chunk-size=2000 -user="temp" 
           -password="test" -host=**.*.*.* \
           -allow-on-master -database="sbtest" -table="sbtest1" \ 
           -alter="engine=innodb" -cut-over=default \ 
           -exact-rowcount -concurrent-rowcount -default-retries=120 \ 
           -timestamp-old-table -assume-rbr -panic-flag-file=/tmp/ghost.panic.flag \ 
           -execute
```
