常用DDL工具详解

gh-ost

由github维护的MySQL online DDL工具,同样使用了镜像表的形式,但是放弃了低效的trigger,而是从binlog中提取需要的增量数据来保持镜像表与原表的数据一致性。整个online DDL操作仅在最终rename源表与镜像表时会阻塞几秒的读写。

原理

  • 在master中创建镜像表(tablename_gho)和心跳表(tablename_ghc)。
  • 向心跳表中写入online DDL的进度以及时间。
  • 在镜像表上执行alter操作。
  • 伪装成slave连接到master的某个slave实例上获取binlog的信息(默认连接slave,也可以连master)。
  • 在master 中完成镜像表的数据同步。
    • 从源表拷贝数据到镜像表
    • 依据binlog信息完成增量数据的变更
  • 在源表上加锁
  • 确认心跳表的时间,确保数据是完全同步的
  • 用镜像表替换源表
  • online DDL完成。
  • 未来考虑会支持的功能或特性:
    • 支持外键
    • gh-ost进程意外中断以后,可以新启动一个进程继续进行online DDL。

使用限制

  • binlog格式必须使用row,且binlog_row_image必须是FULL。
  • 需求的权限为SUPER, REPLICATION CLIENT, REPLICATION SLAVE on . and ALL on dbname.*
    • 如果确认 binlog 的格式为 row,那么可以加上 -assume-rbr,则不再需要 super 权限。
    • 由于不支持 REPLICATION 相关的权限,TiDB 无法使用。
  • 不支持外键。
    • 不论源表是主表还是子表,都无法使用。
  • 不支持触发器。
  • 不支持包含 JSON 列的主键。
  • 迁移表需要有显示定义的主键,或者有非空的唯一索引。
  • 迁移工具不区分大小写英文字母,如果存在同名,但是大小写不同的表则无法迁移。
  • 迁移表的主键或者非空唯一索引包含枚举类型时,迁移效率会大幅度降低。

使用注意

  • 如果源表有非常多的数据,尽量分批次删除。
    • delete from table tablename_old limit 5000;
    • 或者在业务空闲时段用truncate table tablename_old清空表数据之后再 drop 表。
  • 单个 MySQL 实例上启动多个 gh-ost 来进行多个表的 Online DDL 操作时要制定-replica-server-id参数
  • 务必注意可用的磁盘空间,尤其是操作大表的时候。
    • gh-ost 的镜像表包含源表的所有数据,会额外占用一倍的磁盘。
    • gh-ost 在操作的过程中会产生大量的 binlog,且binlog_row_image必须为 FULL,会占用比较多的磁盘空间。
  • rename 列的操作可能会有问题,考虑 drop 和 add 的操作结合起来。
  • 默认会用同样的账号名和密码同时连接 master 和 slave,因此方便起见,直接用高权限账号会比较好。

总结

gh-ost输出的信息,迁移数据的效率,以及支持的功能都比pt-osc等工具要优秀,而gh-ost工具的问题(磁盘空间)在其他工具也会遇到,因此在DDL操作又想避免延迟等问题时,推荐优先考虑gh-ost。

pt-osc

原理

  1. 创建一个与原表结构相同的空表,表名是_new后缀。
  2. 修改步骤1创建的空表的表结构
  3. 在原表上加三个触发器:delete/update/insert,用于copy数据过程中,将原表中要执行的语句在新表中执行。
  4. 将原表数据以数据块(chunk)的形式copy到新表。
  5. rename原表为old表,并把新表rename为元表名,然后删除旧表。
  6. 删除触发器

限制

  1. 原表上要有primary key 或unique index,因为当执行该工具时会创建一个delete触发器来更新新表。

注意:一个例外的情况是–alter,指定的子句中是在原表的列上创建primary key或unique index,这种情况下将使用这些列用于delete触发器。

  1. 不能使用rename子句来重命名表
  2. 列不能通过删除+添加的方式来重命名,这样将不会copy原有列的数据到新列。
  3. 如果要添加的列是not null,则必须指定默认值,否则会执行失败。
  4. 删除外键约束(DROP FOREIGN KEY constraint_name),外键约束名前面必须添加一个下划线 ‘_’,即需要指定名称 _constraint_name,而不是原始的 constraint_name;

如何选择

  • pt-osc、gh-ost、原生online DDL copy,都需要copy原表数据到一个新表,这个是非常耗时的。
  • pt-osc采用触发器实现应用DDL期间的DML,gh-ost通过binlog应用DDL期间的DML,理论上触发器会有一定的负载,且gh-ost可以从从库上拉去binlog,对主库的影响更小。
  • 原生online DDL中inplace方式,对于no-rebuild方式,不需要重建表,只需要修改表的源数据,非常快
  • 原生online DDL中inplace方式,对于rebuild方式,需要重建表,但是也是在InnoDB内部完成的,比copy的方式要快。

如何选择?

  1. 如果MySQL版本是5.6之前,不支持online DDL,选用第三方工具pt-osc或gh-ost
  2. 如果MySQL版本是5.6以上,对于使用copy table方式的DDL,不支持online,使用第三方工具pt-osc或gh-ost;
  3. 对于可以使用inplace no-rebuild方式的DDL,使用原生online DDL。
  4. 对于使用inplace rebuild table方式的DDL,如果想使DDL过程更加可控,且对从库延迟比较敏感,使用第三方工具pt-osc或gh-ost,否则使用原生online DDL。
  5. 对于想减少对主库的影响,实时交互,可以选用gh-ost
Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计