本月初,GitHub 数据库基础架构组的高级软件工程师 Shlomi Noach 在 GitHub Engineering 网站上发文宣告了gh-ost 的开源发布。这对MySQL 社区是一件大事,宣告停滞许久的MySQL 表在线修改表定义操作又有了新的解决方案。
Shlomi 这样总结:
gh-ost 是 GitHub 最近几个月开发出来的,目的是解决一个经常碰到的问题:不断变化的产品需求会不断要求更改 MySQL 表结构。gh-ost 通过一种影响小、可控制、可审计、操作简单而且安全的方式来改变线上表结构。
目前,MySQL 在线修改表定义的任务主要是通过这三种途径完成的:
- 在从库上修改表定义,修改之后再提升为新的主库。
- 通过 MySQL 5.6 开始提供的 InnoDB 在线 DDL 功能。
- 使用修改表定义工具。现在最流行的是 Percona 公司的 pt-online-schema-change 和 Facebook 的 OSC ,也有人使用 LHM 或最早的 oak-online-alter-table 。
在从库上修改表定义的方案耗时长,需要更多的服务器,这种方案需要非常细致的管理工作,并且修改完毕后主从切换过程也会造成短暂的停服。InnoDB 在线 DDL 功能在主库上操作的确是可以满足需求的,但过程不可中断,并且操作完成会造成主从库之间较大的延迟,对许多高可用方案及读写分离等会造成较大困扰。被各大公司 DBA 广泛接受的作法主要是通过 Percona 公司的 pt-online-schema-change 和 Facebook 的 OSC 在线操作。
所有在线更改表定义的工具运行原理都是相似的:创建一张与原始表定义相同的临时表,趁上面没有数据时先把临时表改好表定义,然后慢慢地、用增量方式把数据从原始表拷到临时表,同时不断地把进行中的原始表上的数据操作(所有应用在原始表上的插入、删除、更新操作)也应用过来。当工具把所有数据都拷贝完毕,两边数据同步了之后,它就用这张临时表来替代原始表。修改过程就结束了。
像 pt-online-schema-change、LHM 和 oak-online-alter-table 这些工具用的都是同步复制的方式,对表的每一条数据修改都会立刻在同一个事务里就应用到临时表上。Facebook 的 OSC 工具用的则是异步模式,先把修改操作都记在一张修改日志表里,然后再取出来执行,把修改操作应用到临时表上。这些工具全都使用触发器来提取那些应用在目标表上的操作。
除了在修改过程中的性能、运维等问题之外,在最后的表切换——用临时表替代原始表——的过程中也非常容易出各种问题:切换失败、丢数据、阻塞原始表业务操作过久等。为此 Shlomi 曾在博客上基于较优的 Facebook OSC 的行为连续写了三篇文章(一、二、三)进行分析,进行了细致讨论,并最终给出了一种比较简单而又无损的方案。
GitHub 每天数据库基础架构组几乎每天都会收到几次对表结构进行修改的请求,因此各种可能的丢失数据、复杂管理、进度不可见等行为都是不可忍受的。最终他们经过周密的讨论、研发和测试,推出了自己的工具:gh-ost,这个名字是 gitHub’s Online Schema Transmogrifier/Transfigurator/Transformer/Thingy 的缩写,读音同 Ghost。
gh-ost 有以下特点:
- 无触发器:这也是其他工具最受诟病之处。触发器方案会对 MySQL 的性能造成比较大的影响,严重时甚至会拖垮主库。
- 轻量级:gh-ost 获取数据表修改操作的方法是伪装成从库连入,获取并解析二进制日志,对临时表插入数据也是增量、可控制的,因此对 MySQL 主库的性能几乎无影响。
- 可暂停:当原主库处于业务高峰期时,完全可以暂停 gh-ost 的操作,暂停就意味着对主库没有写入和更新,这是非常受欢迎的。
- 动态可控:gh-ost 的操作不但可以暂停,还可以动态修改,因此在各种情况下修改了配置之后都不必从头开始重新运行整个修改过程,这是非常节约资源的。
- 可审计:gh-ost 的状态是可以非常容易获取到的,包括当前任务进度、主要配置参数、相关 MySQL 实例的情况等。gh-ost 通过监听 TCP 或者 unix socket 文件来获取命令,因此就给了运维人员极大的灵活性。
- 可测试:gh-ost 支持在从库上进行测试,以观察对系统负载的影响、验证正确性等。GitHub 生产环境的每一张表都这样用 gh-ost 在从库上做过好多次修改测试,他们也呼吁大家用这种方式先体验 gh-ost 的功能,再考虑上线应用。
- 可靠性高:经过充分的测试之后,现在 GitHub 生产环境的修改表定义操作已经全部由 gh-ost 完成了,而且它还有暂停、延迟切换、准确估计任务进度等功能,审计和在线控制功能可以让它轻松地与监控系统结合起来,必然非常受运维人员喜爱。
- 完美解决切换问题:表切换操作是在线修改表定义的最后一步,其它工具操作到这一步时常常会出现各种问题。Facebook OSC 也曾详细分析过这个问题,但它的最终方案是个非原子性切换:先把原始表改名,再把临时表改名顶上。可惜在两次改名中间会有一小段表不存在的时间,在这期间运行的业务语句都会失败,因为目标表不存在。Shlomi 等经过严密的论证和实验,给出了原子性的两阶段切换方案:用一条连接去持有锁,另一条连接做原子性的 rename 操作。在 rename 操作之前,会创建一张信号表,用它来阻塞 rename 操作,直到所有要求的表切换前提条件就绪。根据这个方案,表切换或者成功,皆大欢喜;或者失败,则对业务无影响,也不会丢失数据,还会释放锁让业务继续,DBA 只需要再一次用 gh-ost 重新尝试切换即可。
gh-ost 按照 MIT 许可协议向开源社区发布。尽管现在已经稳定了,GitHub 仍在计划继续改进它,也非常欢迎来自开源社区的力量来一起试用和提出改进意见。gh-ost 是用GO 语言实现的。
感谢杜小芳对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ , @丁晓昀),微信(微信号: InfoQChina )关注我们。
评论