官方地址:GitHub - github/gh-ost: GitHub's Online Schema-migration Tool for MySQL
使用ghost方式在线对mysql表进行ddl
ghost原理:
- 要对表A进行DDL,在主库建立一个ghost表 A1
- 在表A1上进行alter操作
- 伪装成一个mysql的从库,监听一个真正从库的binlog
- from 从库获取binlog(默认方式,尽量不影响主库),不断的把 binlog apply 回 ghost表上
- cut-over 是最后一步,锁住主库的源表,等待 binlog apply 完毕,然后替换 gh-ost 表为源表(这里有个秒级的阻塞,表不可用)。gh-ost 在执行中,会在原本的 binlog event 里面增加以下 hint 和心跳包,用来控制整个流程的进度,检测状态等。
注意事项:
1、DDL需要新建一张ghost表,如果表数据很大,需要提前考虑磁盘空间是否足够;
2、binlog apply到主库的ghost表中,注意限流,避免将资源占满,影响线上操作;
踩坑
1、对表进行ddl操作时,现在测试环境进行ddl操作,无问题
2、公司线上环境全球存在4个库,中国、美国、新加坡、日本,只有中国库中的A表进行了分片,其他库未分片,优先对海外3个库进行ddl操作,都无问题;
3、晚上对中国库中的表进行ddl操作,操作开始后,系统报错开始增多,查看日志发下是db proxy层报的错;错误显示 各分片中存在表字段不一致的请求;(分片库DDL,一个个分片进行DDL,必然会不一致啊,凌乱了。。。,这岂不是说分片库不能进行ddl操作,纳尼。。。)
4、拉起oncall,与dba一起进行分析,发现是db proxy层对请求进行了拦截处理,因为proxy在对分片数据进行聚合时,发现字段不一致,有的表新增了字段,有的表还没执行ddl;这符合预期啊
5、分析是sql存在select * from table ... 造成,select * 包含了新增字段,proxy层进行数据merge时,字段不一致,无法merge,直接报错给业务系统;
6、总共有101个分片,此时,部分分片表执行完了DDL,不分未执行DDL,停止执行DDL也无法使系统恢复,要么将已加的字段重新发起一个删除字段的DDL,要不继续执行,别无它法;我们选择让DDL继续执行,还好我们这里有容灾手段,相当于对该表进行了降级处理,并且此时为晚间业务低峰期;
综上:这个问题对于业务系统来说,是比较被动的,第一无法避免该问题,毕竟并不知道db proxy层会有这个策略;改进点:
1、db proxy对该种方式会拒绝,那么就应该阻止此类DDL的执行;
2、业务系统改造,对所有会生成select * 的语句都处理掉,必须select 具体字段,这样就不会应用上新字段;
3、db proxy扫描所有业务分片表的select语句,存在select * 的都应该改造,避免再出现此类问题;