gh-ost菜鸟教程
目录
前言
原理
过程
安装
实战(单节点)
前言
gh-ost
是 GitHub 开发的一款用于 MySQL 数据库的在线模式迁移解决方案,它支持无触发器的在线模式迁移。这个工具是可测试的,并提供暂停、动态控制/重新配置、审计以及许多操作特权。gh-ost
旨在改变表迁移的范式,它在迁移过程中对主服务器产生的工作量很小,并且与已迁移表上的现有工作负载分离,从而减少对数据库性能的影响。
原理
主要实现原理,首先建两张表,一张_gho的影子表,gh-ost会将原表数据以及增量数据都应用到这个表,最后会将这个表和原表做次表名切换,另一张是_ghc表,这个表是存放changelog的数据,包括信号标记,心跳等。其次 ,gh-ost会开两个goroutine,一个用于拷贝原表数据,一个用于apply增量的binlog到_gho表,并且两个goroutine的并行在跑的,也就是不用关心数据是先拷贝过去还是先apply binlog过去。因为这里会对insert语句做调整,首先我们拷贝的insert into会改写成insert ignore into,而binlog内insert into会改写成replace into,这样可以很好的支持两个goroutine的并行。但这样的调整能适用所有的DDL吗?答案是否定的。最后,当原表数据全部拷贝完成后,gh-ost会进入到表交换阶段,采用更加安全的原子交换。
过程
- 检查有没有外键和触发器。
- 检查表的主键信息。
- 检查是否主库或从库,是否开启log_slave_updates,以及binlog信息
- 检查gho和del结尾的临时表是否存在
- 创建ghc结尾的表,存数据迁移的信息,以及binlog信息等
---以上校验阶段 - 初始化stream的连接,添加binlog的监听
---以下迁移阶段 - 创建gho结尾的临时表,执行DDL在gho结尾的临时表上
- 开启事务,按照主键id把源表数据写入到gho结尾的表上,再提交,以及binlog apply。
---以下cut-over阶段 - lock源表,rename 表:rename 源表 to 源_del表,gho表 to 源表。
- 清理ghc表
安装
由于gh-ost是基于go1.5编译的,故安装gh-ost之前需要安装go,安装go(我的yum仓库中有go包,故直接使用yum安装,没有的话需要进行下载tar包源码安装)
验证go是否安装成功
go env
接下来安装gh-ost,由于gh-ost的tar包再github中,下载的时候可能由于网络的原因导致下载失败,故我们使用gitee中的项目
https://gitee.com/mirrors/gh-ost
我这里直接下载的zip包,然后上传到服务器
下载到服务器上后进行解压
unzip gh-ost-master.zip
解压之后进入gh-ost-master目录,
然后再当前的目录下初始化一个git仓库
git init
然后需要在build.sh中指定gh-ost版本
打开build.sh脚本设置你需要的gh-ost版本,然后保存,
RELEASE_VERSION=v1.1.7
然后运行build.sh脚本
接下来解压适用于你操作系统的tar包,
tar xvzf gh-ost-binary-linux-amd64-20251022142618.tar.gz
最后将gh-ost二进制文件移动到/usr/local/bin下,然后使用gh-ost --version验证gh-ost是否安装成功
mv gh-ost /usr/local/bin/
gh-ost --version
实战(单节点)
我们创建了一个example_table表,然后使用gh-ost删除这个表中的全文索引ftx_first_name
CREATE TABLE example_table(id INT AUTO_INCREMENT,first_name VARCHAR(50),last_name VARCHAR(50),email VARCHAR(100),created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,status ENUM('active', 'inactive') DEFAULT 'active',PRIMARY KEY (id),INDEX idx_last_name (last_name), FULLTEXT INDEX ftx_first_name (first_name),INDEX idx_status (status),INDEX idx_created_at (created_at),INDEX idx_first_name_last_name (first_name, last_name)
);
gh-ost \
--host=127.0.0.1 \
--user=root \
--password=123456 \
--database=demo1 \
--table=example_table \
--alter="DROP INDEX ftx_first_name" \
--execute \
--allow-on-master
可以看到example_table中的全文索引ftx_first_name已经删除
通过解析binlog我们可以看到首先gh-ost创建了存放changelog的`demo1`.`_example_table_ghc`表,然后创建了影子表`demo1`.`_example_table_gho`
create /* gh-ost */ table `demo1`.`_example_table_ghc` (id bigint unsigned auto_increment,last_update timestamp not null DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,hint varchar(64) charset ascii not null,value varchar(4096) charset ascii not null,primary key(id),unique key hint_uidx(hint)) auto_increment=256 comment='gh-ost changelog'
/*!*/;
随后在影子表`demo1`.`_example_table_gho`执行了ddl,并设置了AUTO_INCREMENT
binlog中继续往下看,在end_log_pos 18708,又创建了`demo1`.`_example_table_del`
create /* gh-ost */ table `demo1`.`_example_table_del` (id int auto_increment primary key) engine=InnoDB comment='ghost-cut-over-sentry'
/*!*/;
在end_log_pos 24355,删除了`_example_table_del`
在end_log_pos 25086,使用rename了
将`demo1`.`example_table` 重命名为`demo1`.`_example_table_del`
将`demo1`.`_example_table_gho`重命名为`demo1`.`example_table`
最后删除了 `_example_table_ghc`和 `_example_table_ghk`