除了MySQL原生的Online DDL,目前业界使用最多的改表工具主要有两款:Percona的pt-osc和GitHub的gh-ost。
1、pt-osc
工作原理:
1、如果存在外键,根据alter-foreign-keys-method参数的值,检测外键相关的表,做相应设置的处理。没有使用 –alter-foreign-keys-method=rebuild_constraints 指定特定的值,该工具不予执行。
2、创建一个和源表表结构一样的临时表(_tablename_new),执行alter修改临时表表结构。
3、在原表上创建3个于inser delete update对应的触发器。(用于copy 数据的过程中,在原表的更新操作 更新到新表)
4、从原表拷贝数据到临时表,拷贝过程中在原表进行的写操作都会更新到新建的临时表。
5、修改外键相关的子表,根据修改后的数据,修改外键关联的子表。
6、rename源数据表为old表,把新表rename为源表名,并将old表删除。
7、删除触发器。
使用限制:
- 表必须有主键或唯一索引
- 表上必须没有触发器
- innodb_autoinc_lock_mode必须为2,否则会严重降低MySQL性能。
2、gh-ost
gh-ost采用的是binlog+回放线程来替换掉触发器。
工作原理:
如下图:
1、先连接到主库上,创建临时的ghost表,根据alter语句修改新表。
2、作为一个“备库”连接到主库(或者某一个备库上),一边在主库上拷贝已有的数据到新表,一边从主库(或者某一个备库)上拉取增量数据的binlog。
3、然后不断的把 binlog 应用回主库。
4、cut-over是最后一步,锁住主库的源表,等待binlog 应用完毕,然后替换gh-ost表为源表。
3、性能测试
使用sysbench表进行测试:
CREATE TABLE sbtest1
(
id
int(11) NOT NULL
AUTO_INCREMENT,
k
int(11) NOT NULL
DEFAULT ‘0’,
c
char(120) NOT NULL
DEFAULT ”,
pad
char(60) NOT NULL
DEFAULT ”,
c1
varchar(100)
DEFAULT NULL,
PRIMARY KEY (id
),
KEY k_1
(k
)
) ENGINE=InnoDB AUTO_INCREMENT=1000001 DEFAULT CHARSET=utf8mb4
测试表原始数据:1000000行。
测试对比业务发生crash时的sql语句:1、重组:alter table sbtest1 engine=innodb,algorithm=inplace,lock=none;2、加字段:alter table sbtest1 add column c1 varchar(100),algorithm=inplace,lock=none;
分别测试无负载、低负载、高负载时改表性能:
- 重组:
- 加字段:
重组与加字段表现基本一致:
执行时间:online ddl < pt-osc < gh-ost
对业务性能影响:gh-ost < online ddl < pt-osc
4、测试小结
pt-osc:
存在1节中的使用限制。由于会在原表上创建3个触发器,触发器有可能导致数据库产生死锁,存在较大风险。且三者中对业务性能影响最大。
online ddl:
在高负载时会有超过10s的时间qps为0,影响业务使用:
gh-ost:
由于采用单线程回放binlog,会导致高负载时一直无法追上数据更新,无法结束改表操作,降低或停止复制后即可正常结束。
测试过程中会在日志中打印一些错误,但报错不影响程序功能:
3.2、gh-ost能支持的最大qps
write qps | 执行时间 |
2400 | 73 |
2700 | 128 |
3000 | 无法结束 |
当前场景下,测试gh-ost最大支持写qps 约2700。