暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

OnLine DDL 工具怎么用?怎么选?(下)

Ty3306 2022-07-05
1782

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参数

  1. LOCK=NONE:允许并发的查询和DML操作

  2. LOCK=SHARED:允许并发的查询,但阻塞DML操作

  3. LOCK=DEFAULT: 由系统决定,允许尽可能多的并发性(并发查询、DML或两者)。如果省略LOCK⼦句相当于指定 LOCK=DEFAULT

  4. LOCK=EXCLUSIVE:阻塞并发查询和DML操作。

ALGORITHM参数

  1. ALGORITHM=COPY:采⽤拷表⽅式进行表变更,与pt-osc/gh-ost类似;

  2. ALGORITHM=INPLACE:仅需要进行引擎层数据改动,不涉及Server层;


COPY TABLE流程

  1. ⾸先建⽴临时表,表结构为ALTAR TABLE更改后的结构

  2. 将原表中数据导⼊到临时表(server层创建临时表,会有显⽰的IBD⽂件)

  3. 删除原表

  4. 将临时表rename为原来的表名

同时这⼀过程中,为了保持数据的⼀致性,中间复制数据时(Copy Table)全程锁表只读,如果有写请求进来将⽆法提供服务,将导致连接数爆张。


IN-PLACE流程

  1. 建⽴⼀个临时⽂件,扫描原表主键的所有数据页

  2. ⽤数据页中原表记录生成B+树,存储到临时⽂件中(innodb_temp_data_file_path临时表空间下创建临时⽂件)

  3. 生成临时⽂件的过程中,将所有对原表的操作记在⼀个⽇志⽂件(rowlog)中

  4. 临时⽂件生成后,将⽇志⽂件中的操作应⽤到临时⽂件,得到⼀个辑数据上与原表相同

  5. 数据⽂件(⽇志⽂件记录和重放操作)

  6. ⽤临时⽂件替换原表数据⽂件

这⼀过程中,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:

  1. 按照原表定义创建一个新的临时表

  2. 对原表加写锁(禁止 DML,允许 select)

  3. 步骤 1)建立的临时表执行 DDL

  4. 将原表中的数据 copy 到临时表

  5. 释放原表的写锁

  6. 将原表删除,并将临时表重命名为原表

可见,采用 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 其大致流程如下:

  1. 建立一个临时文件,扫描表 A 主键的所有数据页;

  2. 用数据页中表 A 的记录生成 B+ 树,存储到临时文件中;

  3. 生成临时文件的过程中,将所有对 A 的操作记录在一个日志文件(row log)中;

  4. 临时文件生成后,将日志文件中的操作应用到临时文件,得到一个逻辑数据上与表 A 相同的数据文件;

  5. 用临时文件替换表 A 的数据文件。

说明:

  1. 在 copy 数据到新表期间,在原表上是加的 MDL 读锁(允许 DML,禁止 DDL)

  2. 在应用增量期间对原表加 MDL 写锁(禁止 DML 和 DDL)

  3. 根据表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相似。




「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论