揭秘MySQL生态重要功能,X-Engine引擎核心能力——OnlineDDL( 二 )


揭秘MySQL生态重要功能,X-Engine引擎核心能力——OnlineDDL
本文插图
整个Inplace-Build按照时间序有3个关键节点 , t0时刻是获取快照的时间点 , t1时刻是build基线完成的时间点 , t2时刻是唯一约束检查完成的时间点 。 那么两个阶段的主要逻辑如下:t0-->t1主要工作是在build新表的基线 , 通过将old-table的数据结合new-table的数据字典生成新的记录 , 最终写入新表对应的L2层;在build新表基线的过程中 , 产生的增量写入到新表的(Mem,L0,L1) 。 DDL过程中 , 需要对后台的Compaction任务做一定的控制 , 确保不执行合并到L2的Compaction任务 。 t1-->t2是唯一性校验阶段 , 确保新增的主键或者唯一索引的唯一性 , t2时刻将(Mem,L0,L1,L2)中的数据合并 , 最终得到new-table的全量数据 。 记录转换的过程如下:
揭秘MySQL生态重要功能,X-Engine引擎核心能力——OnlineDDL
本文插图
其中 , DDL事务表示DDL线程 , 它的任务是扫描基线 , 生成新表的基线数据;DML事务表示DDL过程中 , 并发的DML事务 , 它们的任务是 , 通过双写机制同时维护新表和老表的增量 。
对比InnoDB实现逻辑
虽然X-Engine与InnoDB的OnlineDDL都是采用基线+增量的方式实现 , 但具体逻辑是不同的 , 主要是因为InnoDB采用的的是原地更新操作并且通过row-log机制来维护增量 , 而X-Engine是一个append-only的存储引擎 , 天然地支持数据的多版本存储 , 可以实时维护增量数据 , 在基线建立完成后只需要将基线与增量数据合并 , 即使基线中的数据在增量中被修改 , 但增量中数据的版本比基线数据版本更新 , 从而在合并时会覆盖基线中老版本的数据 。 下图是InnoDB引擎OnlineDDL过程 。
揭秘MySQL生态重要功能,X-Engine引擎核心能力——OnlineDDL
本文插图
可以看到InnoDB引擎的OnlineDDL也包括3个关键时间点 , 与X-Engine引擎的区别在于 , t1-->t2 是InnoDB追row-log过程 , 而对应X-Engine是唯一约束检查的过程 。 当然对于X-Engine来说 , t1-->t2不是必需的 , 因为DDL变更可能并不涉及唯一索引操作 。
Instant-DDL
与MySQL8.0(InnoDB)类似 , X-Engine同样也支持Instant-DDL 。 在所有支持的OnlineDDL中 , 若DDL操作只涉及修改表的属性信息 , 或只是做了加列操作 , 不需要修改记录格式 , 也不需要新增索引 , 那么这些OnlineDDL操作可以优化成Instant-DDL 。 这些DDL操作可以“极速”完成 , 用户基本无感知 。 由于Instant-DDL执行时 , 并没有真正涉及引擎数据的修改 , 为了后续查询结果和DDL操作的正确性 , 需要对于引擎的记录格式做一定的调整 , 加一些控制元信息 。 新增一个1字节来标示生成这个记录时 , 表是否执行过instant-ddl 。 同时 , 生成记录时 , 还需要记录有多少个列是已有的 , 以及有多少个null列等;在读取解析记录时 , 根据字典信息 , 就能知道有多少个列是需要根据instant列信息来补充 , 确保instant-DDL后 , 返回查询结果的正确性 。
DDL原子性保证
从OnlineDDL的整体流程中我们了解到 , OnlineDDL最后一个阶段是Post-ddl阶段 。 MySQL8.0以前 , Server层的元数据都是通过文件来存储 , 比如frm文件 , par文件以及trg文件等 。 一个DDL操作修改 , 涉及到文件修改 , 引擎数据修改以及引擎字典的修改 , 这些操作无法做成一个事务 , 必然导致整个DDL操作无法做到原子性 。 若DDL过程中出现异常 , 就可能会导致Server层和引擎层数据不一致 , 以及残余的垃圾没有清理等问题 。 MySQL8.0将Server层的所有字典信息统一存储在DD(DataDictionary)中 , 并且通过InnoDB引擎存储 , 那么DDL过程中 , 我们只要保证Server层数据字典的修改 , 以及引擎层数据字典的修改封装成一个事务即可 。