gh-ost:用 binlog 替代触发器的 MySQL 在线表结构变更工具
gh-ost 是 GitHub 开源的 MySQL 在线表结构变更(Online Schema Migration)工具,无触发器(triggerless)。迁移过程对主库产生的额外负载较轻,并提供测试、暂停、动态配置、状态查询和 hooks 等运维能力。它的设计出发点来自多年使用同类工具的运维经验:传统方案里的触发器,往往是很多局限与风险的来源。
项目地址:github.com/github/gh-ost。仓库 doc/ 目录下包含 cheatsheet、triggerless-design、why-triggerless、throttle、interactive-commands、hooks、requirements-and-limitations、RDS、Azure 等专题文档。
原理
在线表结构变更的基本路径都是一样的:
- 创建一张与原始表结构一致的
ghost表。 - 在空表上完成结构迁移。
- 将原表已有数据分批复制到 ghost 表。
- 同时把原表上持续的 INSERT / DELETE / UPDATE 变更同步到 ghost 表。
- 在合适的时机用 ghost 表替换原表。
不同工具的区别主要在第 4 步如何捕获变更。大多数既有工具在这一步使用触发器,由数据库在每次 DML 时把变更写入影子表。触发器带来了额外数据库负担,也让迁移过程很难被真正挂起。gh-ost 改为消费 binlog 流来捕获变更,再异步应用到 ghost 表。原本交给数据库做的一部分传播工作移到 gh-ost 自身,于是它能做到:
- throttle 时真正暂停:不做行复制,也不处理持续变更事件,迁移写入可以完全停下来,让主库回到原有工作负载;
- 让迁移写入与业务写入解耦,而不是叠加在同一批触发器执行路径上。
关键特性
- 从库上建立信任:gh-ost 会在从库上执行与主库相同的完整迁移流程,最后不替换原表,从库上会同时保留原表和 ghost 表,方便人工或脚本做 checksum 比对。
- 真正可暂停:throttle 时停止向主库写入迁移数据,不是降低频率,而是完全挂起。
- 动态控制:迁移运行中仍可通过交互式命令重配置、强制触发 throttle。
- 状态查询:可通过 unix socket 或 TCP 查询当前迁移状态。
- 控制 cut-over 时机:可以把最关键的换表步骤推迟,直到操作人员确认在场。
- 外部 hooks:通过 hooks 将 gh-ost 与特定环境的编排逻辑耦合。
常用运行模式
按 gh-ost 的 cheatsheet,运行模式大致分这几类:
--noop:只验证迁移计划和参数是否有效、可执行,不改动线上数据。--test-on-replica:在从库上完整走一遍迁移流程,结束后保留原表和 ghost 表,用于验证、比对、建立信心。- 真实迁移 + 从库配合:迁移在主库执行,gh-ost 自动确认所涉及服务器的身份。若主库使用基于语句的复制(Statement Based Replication),必须使用这种带从库的模式。
- 真实迁移 + 主库直跑:直接在主库执行,gh-ost 更倾向于前一种带从库的方案。
- 直接迁移从库:从库作为迁移目标,主库不参与。
从测试到执行的建议顺序
gh-ost 官方建议把测试放在第一位。一套可复现的上手路径是:
- 先在从库上跑几遍
--test-on-replica。如果有多台从库,可以把目标表批量轮着跑,跑完对原表和 ghost 表做 checksum 校验确认数据一致。 - 对主库发起正式迁移前,先跑一次
--noop,确认这条迁移计划在真实环境里可以成立。 - 用
--execute发起真实迁移。此时可以叠加--exact-rowcount获得精确的行数进度,而不是估算值。 - 如果希望 cut-over 发生在可控时间点,加上
--postpone-cut-over-flag-file:该 flag 文件存在时 gh-ost 会推迟换表,移除文件后才继续执行表交换。 - 迁移运行期间熟悉 interactive commands,用来查看状态、主动 throttle 或动态调整配置。
命名与发布状态
gh-ost 最初叫 gh-osc:GitHub Online Schema Change,命名上对标 Facebook 的 online schema change 工具和 Percona 的 pt-online-schema-change。后来演变为 gh-ost,全称 GitHub's Online Schema Transmogrifier,读音就是 ghost。
项目已 GA。提供 Linux 与 macOS 二进制,Go 1.15+ 构建。master 分支通常处于可用状态,但生产环境请使用 release。License 为 MIT。