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
原理
- 创建一个与原表结构相同的空表,表名是_new后缀。
- 修改步骤1创建的空表的表结构
- 在原表上加三个触发器:delete/update/insert,用于copy数据过程中,将原表中要执行的语句在新表中执行。
- 将原表数据以数据块(chunk)的形式copy到新表。
- rename原表为old表,并把新表rename为元表名,然后删除旧表。
- 删除触发器
限制
- 原表上要有primary key 或unique index,因为当执行该工具时会创建一个delete触发器来更新新表。
注意:一个例外的情况是–alter,指定的子句中是在原表的列上创建primary key或unique index,这种情况下将使用这些列用于delete触发器。
- 不能使用rename子句来重命名表
- 列不能通过删除+添加的方式来重命名,这样将不会copy原有列的数据到新列。
- 如果要添加的列是not null,则必须指定默认值,否则会执行失败。
- 删除外键约束(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的方式要快。
如何选择?
- 如果MySQL版本是5.6之前,不支持online DDL,选用第三方工具pt-osc或gh-ost
- 如果MySQL版本是5.6以上,对于使用copy table方式的DDL,不支持online,使用第三方工具pt-osc或gh-ost;
- 对于可以使用inplace no-rebuild方式的DDL,使用原生online DDL。
- 对于使用inplace rebuild table方式的DDL,如果想使DDL过程更加可控,且对从库延迟比较敏感,使用第三方工具pt-osc或gh-ost,否则使用原生online DDL。
- 对于想减少对主库的影响,实时交互,可以选用gh-ost