安全、高效的 MySQL DDL 解决方案
数据库编程大赛,倒数计时4天报名中!
MySQL作为目前应用最广泛的开源关系型数据库,是许多网站、应用和商业产品的主要数据存储。在生产环境,线上数据库常常面临着持续的、不断变化的表结构修改(DDL),如增加、更改、删除字段和索引等等。其中一些DDL操作在MySQL中会锁表,影响线上服务,那该如何解决DDL期间导致业务不可用的问题呢?我们先来看看当前有哪些解决方案。
本文完整对比了业界常用的Online DDL 工具,并从产品体验、版本支持的完整度、云适配、易用性和性能等多个⻆度进行评估与分析,给出使用推荐:
NineData 是SaaS模式,开箱即用,很好的适配了各主流云的 MySQL 实例并覆盖了所有版本。而 pt-osc 和 gh-ost 都是以命令行方式执行,需要人工介入进行命令拼装,不仅容易出错,而且还需要关心和不同版本的 MySQL 适配,易用性不高。最后,在性能方面,pt-osc 相对最好,原因是和其 Online DDL实现的方式相关。本文在后面会展开对各工具的流程进行说明,方便大家进一步认识他们的实现方式。
01
常用 Online DDL 工具
1.1 pt-online-schema-change
由 Percona 公司开发的一种在线修改表结构的工具,该工具执行的大致流程如下:
整个过程中,通过使用触发器实现增量数据的同步,在数据同步期间,不阻塞该表的DML。但由于表上创建有触发器,如果该表的更新比较频繁很可能出现锁争用问题。
1.2 gh-ost
由 GitHub 开发提供的一种在线修改表结构的工具,该工具执行的大致流程如下:
1. 创建一张影子表(_table_gho),结构和原表保持一致。
2. 在影子表(空表)上做DDL操作。
3. 创建 BinLog Streamer,模拟从库读取实例的binlog,应用增量操作到影子表中执行。
4. 进行全量数据复制,根据主键或唯一键进行分片读取写入(INSERT IGNORE ... SELECT ... LOCK IN SHARE MODE),循环直到全量数据读取同步完毕。
5. RENAME TABLE,影子表和源表相互转换表名(原子性,持有短暂时间的排他锁,阻塞DML)。
6. 停止BinLog Streamer,并删除被改名后的原表。
整个过程中,通过读取binlog来实现增量数据的同步,在数据同步期间,不阻塞该表的DML。由于读取binlog是单线程,所以增量同步的效率不高,但开销最小。
1.3 MySQL Online DDL
在 MySQL5.5 及之前的版本,修改表结构操作(DDL)会阻塞对该表数据的读写操作, 从MySQL5.6开始,提供Online DDL的能力,支持部分的 DDL语句在执行期间不阻塞该表的读写操作,大大降低了 DDL 操作对业务带来的影响。
MySQL DDL操作分为两种:一种是采用 copy table方式(MySQL5.5及之前的版本)的DDL,期间会阻塞该表的读写操作;另一种是采用 inplace 方式(Online,MySQL5.6及之后的版本),该方式分为两类情况::一类是重建表(rebuild table),另一类是只修改表的元数据不需要重建表(no-rebuild table),具体可以查看官网中的「Online DDL Operations」章节。其中:
copy table:在 server 层生成一张临时表,复制原表数据到临时表(ibd、frm),完成后临时表替换原表。复制数据期间阻塞该表的读写操作。
rebuild table :在 engine 层生成原表的临时转储文件(ibd、frm),复制原表数据,完成后临时表替换原表。复制数据期间不阻塞该表的读写操作。
no-rebuild table :在 engine 层生成原表的临时转储文件(frm),不需要复制源表数据,完成后更新表的元数据信息,期间不阻塞该表的读写操作。
copy table 方式的大致流程:
7. 提交和释放锁
整个过程中,通过生成临时表的方式进行数据同步,源表的DML操作会被阻塞,直到全量数据复制完成。通过该方式修改表结构会阻塞读写(DML)操作,所以需要尽量避免该方式进行DDL操作。
inplace 方式的大致流程:
- rebuild table,在 engine 层生成原表的临时转储文件(ibd、frm)
no reduild table,在 engine 层生成原表的临时转储文件(frm)