3. MySQL OnLine DDL
3.1 原理
Online DDL在MySQL 5.6才开始⽀持的,在5.5及之前版本,使⽤alter table/create index等命令进行表结构修改操作均会锁表,这在生产环境上明显是不可接受的。
在MySQL 5.7,Online DDL在性能和稳定性上不断得到优化,性能有显著优势,且对业务负载影响小,停写时间可控,相对pt-osc/gh-ost来说,⽆需安装第三⽅依赖包,同时⽀持Inplace算法的Online DDL,由于⽆需拷表,所需磁盘空间也更小。
先来看⼀个常见的DDL语句:
ALTER TABLE tbl_name ADD PRIMARY KEY (column), ALGORITHM=INPLACE, LOCK=NONE;
其中,LOCK描述了DDL期间运行的并发程度,ALGORITHM描述了DDL的实现⽅式LOCK参数
LOCK=NONE:允许并发的查询和DML操作
LOCK=SHARED:允许并发的查询,但阻塞DML操作
LOCK=DEFAULT: 由系统决定,允许尽可能多的并发性(并发查询、DML或两者)。如果省略LOCK⼦句相当于指定 LOCK=DEFAULT
LOCK=EXCLUSIVE:阻塞并发查询和DML操作。
ALGORITHM参数
ALGORITHM=COPY:采⽤拷表⽅式进行表变更,与pt-osc/gh-ost类似;
ALGORITHM=INPLACE:仅需要进行引擎层数据改动,不涉及Server层;
COPY TABLE流程
⾸先建⽴临时表,表结构为ALTAR TABLE更改后的结构
将原表中数据导⼊到临时表(server层创建临时表,会有显⽰的IBD⽂件)
删除原表
将临时表rename为原来的表名
同时这⼀过程中,为了保持数据的⼀致性,中间复制数据时(Copy Table)全程锁表只读,如果有写请求进来将⽆法提供服务,将导致连接数爆张。
IN-PLACE流程
建⽴⼀个临时⽂件,扫描原表主键的所有数据页
⽤数据页中原表记录生成B+树,存储到临时⽂件中(innodb_temp_data_file_path临时表空间下创建临时⽂件)
生成临时⽂件的过程中,将所有对原表的操作记在⼀个⽇志⽂件(rowlog)中
临时⽂件生成后,将⽇志⽂件中的操作应⽤到临时⽂件,得到⼀个辑数据上与原表相同
数据⽂件(⽇志⽂件记录和重放操作)
⽤临时⽂件替换原表数据⽂件
这⼀过程中,alter 语句在启动的时候获取MDL写锁,但是这个写锁在真正拷贝数据之前就退化成读锁,也就是说在最耗时的copy数据到临时⽂件的过程中,原表是可以进行dml操作的,仅仅会在最后的新旧表切换阶段加锁,这个rename的时间就⾮常快了。
允许并发DML的DDL操作
创建/新增⼆级索引
重命名⼆级索引
删除⼆级索引
改变索引类型(USING {BTREE | HASH})
添加主键(expensive cost)
删除主键并增加另⼀个(expensive cost)(ALTER TABLE tbl_name DROP PRIMARY KEY, ADD PRIMARY KEY
(column), ALGORITHM=INPLACE, LOCK=NONE;)
新增列(expensive cost)
删除列(expensive cost)
重命名列
列重新排序(expensive cost)
改变列默认值
删除列默认值
改变列⾃增值
设置列属性null/not null (expensive cost)
修改枚举或集合列的定义
Change ROW_FORMAT
Change key block size
标记为expensive cost的操作虽然允许OnlineDDL,但本⾝对服务器IO,CPU都会造成较⾼负担,同时会导致复制阻塞,造成另⼀种形式的从库复制延迟,所以如果是⼤表,建议业务低峰期执行
不允许并发DML的DDL操作
添加全⽂索引
添加空间索引
删除主键
改变列数据类型
添加⾃增列(新增列->变为⾃增列)
变更表字符集
修改数据类型长度
特例:varchar字符长度从10变更到小于255 采⽤inplace⽅式不会锁表;从255变更到10会锁表;
自 MySQL 5.6 起,MySQL 原生支持 Online DDL,即在执行 DDL 期间允许执行 DML(insert、update、delete)。了解 Online DDL 先了解一下之前 DDL 的 2 种算法 copy 和 inplace。
Copy:
按照原表定义创建一个新的临时表
对原表加写锁(禁止 DML,允许 select)
步骤 1)建立的临时表执行 DDL
将原表中的数据 copy 到临时表
释放原表的写锁
将原表删除,并将临时表重命名为原表
可见,采用 copy 方式期间需要锁表,禁止 DML,因此是非 Online 的。比如:删除主键、修改列类型、修改字符集,这些操作会导致行记录格式发生变化(无法通过全量 + 增量实现 Online)。
Inplace:
在原表上进行更改,不需要生成临时表,不需要进行数据 copy 的过程。
根据是否行记录格式,分为两类:
rebuild:需要重建表(重新组织聚簇索引)。比如 optimize table、添加索引、添加/删除列、修改列 NULL/NOT NULL 属性等;
no-rebuild:不需要重建表,只需要修改表的元数据,比如删除索引、修改列名、修改列默认值、修改列自增值等。
对于 rebuild 方式实现 Online 是通过缓存 DDL 期间的 DML,待 DDL 完成之后,将 DML 应用到表上来实现的。例如,执行一个 alter table A engine=InnoDB; 重建表的 DDL 其大致流程如下:
建立一个临时文件,扫描表 A 主键的所有数据页;
用数据页中表 A 的记录生成 B+ 树,存储到临时文件中;
生成临时文件的过程中,将所有对 A 的操作记录在一个日志文件(row log)中;
临时文件生成后,将日志文件中的操作应用到临时文件,得到一个逻辑数据上与表 A 相同的数据文件;
用临时文件替换表 A 的数据文件。
说明:
在 copy 数据到新表期间,在原表上是加的 MDL 读锁(允许 DML,禁止 DDL)
在应用增量期间对原表加 MDL 写锁(禁止 DML 和 DDL)
根据表A重建出来的数据是放在 tmp_file 里的,这个临时文件是 InnoDB 在内部创建出来的,整个 DDL 过程都在 InnoDB 内部完成。对于 server 层来说,没有把数据挪动到临时表,是一个原地操作,这就是“inplace”名称的来源。
3.2 用法
mysql> alter table qa modify y11 varchar(13) not null default "",algorithm=inplace,lock=none;
3.3 Online DDL的优缺点与后续优化
优点
综合上面的分析,目前Online DDL的优势包括: - 性能有显著优势,且对业务负载影响小,停写时间可控; - 操作简单,直接执行alter table或类似命令即可,无需安装第三方工具和依赖包; - 所需存储空间少,pt-osc/gh-ost均需要创建新表并拷贝数据,因此需要有不小于表大小的空闲存储空间。但对于加列和加索引等支持Inplace算法的Online DDL,无需拷表,空间大大节省; - 不会产生大量binlog,pt-osc/gh-ost拷表时会产生大量binlog文件,这即增大了最多表空间大小一倍的存储空间,而且也容易造成复制延迟,降低了从库的可读性,放大了服务不可用风险。
缺点
似乎Online DDL仅有的缺点是会导致复制阻塞,造成另一种形式的从库复制延迟。其示意图如下:

主库上ddl和dml可以并发执行,在group commit阶段依次写入到binlog文件中,这些binlog传到从库上,由并行复制的worker线程回放。
通俗来说,由于并行复制是以group为单位进行回放的,ddl作为单独一个group,只有执行完才能进行下一个group回放,这意味在主库上与ddl差不多时间提交但binlog写在ddl之后的那些dml,其复制延迟会大于ddl的执行时间。
4. DDL工具性能对比测试
测试时,我们使用sysbench来模拟有无业务负载的场景。DDL操作考虑加列和加索引这两种。测试数据量为1k万条记录。测试结果如下。
4.1 无负载测试

从图中可以看出,Online DDL的性能明显好于2种第三方工具。
4.2 有负载测试
负载配置:
oltp.lua --oltp_tables_count=4 --oltp-table-size=10000000 --rand-init=on --num-threads=32
负载tps值约6k:

测试时,pt-osc和Online DDL均顺利完成,但gh-ost无法结束,将并发数调整为5后才达到与pt-osc相似的性能表现。 gh-ost负载配置:
oltp.lua --oltp_tables_count=4 --oltp-table-size=10000000 --rand-init=on --num-threads=5
性能测试结果如下:

综合考虑有无负载情况,Online DDL的性能均大大优于2种第三方工具,进一步对比在这2种工具。可以看到pt-osc在性能和高负载情况下的稳定性均好于gh-ost。
4.3 DDL操作对业务负载的影响
Online DDL执行期间对业务负载影响较小,从6k降为5.8k左右。但在切换阶段会出现秒级地停写情况,如下所示:

pt-osc对业务负载的影响相比Online DDL和gh-ost都大,操作期间,性能从6k降为5.2k左右。

gh-ost虽然在高业务负载情况下无法完成DDL操作,但对性能的影响较小,与Online DDL相近,但其也不会出现停写情况,这与pt-osc相似。





