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


概述
X-Engine是阿里自研的数据库存储引擎 , 以插件的方式接入到MySQL生态 , 支持行锁 , 事务 , MVCC等OLTP场景的核心功能 。
X-Engine的核心优势是低成本 , 高性价比 , 尤其适用于历史库场景 , 目前阿里巴巴内部的核心交易历史库(原来是Hbase) , 钉钉消息历史库(原来是MySQL(InnoDB)) , 淘宝商家的图片空间等业务均通过X-Engine解决了成本问题 。
同时 , X-Engine也赋能阿里云数据库服务 , 作为云上RDS-MySQL的存储引擎 , 对外售卖 , 让更多的用户享受到新技术带来的红利 , 有关X-Engine的详细介绍 , 请移步2019年10月的数据库内核月报 。 本文主要介绍X-Engine引擎的一个核心功能 , OnlineDDL 。
OnlineDDL毫无疑问是MySQL生态的一个重要的功能 , 想当初MySQL 5.6以前 , DBA执行DDL变更时 , 为了保证7*24小时服务 , 只能采用最老土的主备切换的方式来进行 。 数据库存储引擎区别于NoSQL引擎的一种重要指标就是是否支持SQL , 是否有schema(数据字典) 。 有了schema , 还需灵活地支持在线变更 , 这样才能从容应对业务快速变化的需求 。 MySQL生态中这么多存储引擎只有InnoDB完整地支持了OnlineDDL , X-Engine作为MySQL生态的新成员 , 虽然采用了完全不同于InnoDB的存储架构 , 但OnlineDDL给用户的体验是一样的。
整体流程
X-Engine采用类LSM的分层架构 , 数据按照时序逻辑分成多层 , 每一层数据有序 , 新数据在较高的层次 , 最老的历史数据在最底层 。 对于X-Engine来说 , 每个主表和二级索引数据都是一棵分层的LSM-tree结构 , 内部称之为Subtable 。 每个Subtable分为4层 , Memtable , L0 , L1和L2 , 每一层都保持有序 , 数据按新旧顺序依次往更深的层次迁移 , 其中Memtable在内存中 , 其它几层按需可以在不同的存储介质上 。 OnlineDDL功能实现充分利用了X-Engine的数据组织特点 , 将新build数据分为两部分 , 基线数据和增量数据 。 基线数据是指变更开始时 , 通过拿snapshot能遍历得到的数据;增量数据是指 , 变更开始后 , 用户写入的新数据 。 拿Snapshot过程需要短时间禁写 , 因为我们强依赖这个一致性位点 , 确保基线+增量数据的完整性 。
OnlineDDL总共包括了4个阶段 , 包括Prepare阶段 , Inplace-build阶段 , Commit阶段和Post-ddl阶段 。 1.Prepare阶段 , 这个阶段主要是准备数据字典 , 构建底层存储数据的Subtable , 为后续的增量写入做准备 。
2.Inplace-build阶段 , 这个阶段OnlineDDL的核心阶段 , 一方面通过Snapshot获取基线 , 另一方面还需要实时维护增量数据 , 利用X-Engine的数据组织的append-only特性 , 将基线和增量合并 , 即完成了OnlineDDL新数据构建的过程 。 这个过程的详细逻辑会在下一个小节详细介绍 。
3.Commit阶段 , 这个阶段是OnlineDDL引擎层变更生效阶段 , 如果整个OnlineDDL过程中没有出现异常或错误 , 那么Commit阶段会生效新的数据字典 , 生效新的数据 。
4.Post-ddl阶段 , 这个阶段是OnlineDDL真正生效阶段 , 这个阶段完成后 , 才会返回给用户DDL成功 。 这个阶段的引入 , 主要是因为MySQL通过Server层+引擎层这样的一个二层结构实现扩展 , 而每一层都有自己的数据字典 , 在Commit阶段只能保证引擎层的数据和数据字典是完整的 , 为了保证DDL变更的原子性(Server层和引擎层数据字典保持一致) , 引入Post-ddl阶段做清理和善后工作 , 有关DDL原子性的讨论会在下面的章节详细介绍 。
核心逻辑
OnlineDDL的核心逻辑在于如何做到执行DDL变更时 , 不堵塞用户对该表的DML和SELECT操作 。 X-Engine实现OnlineDDL有两个关键点 , 第1 , 利用X-Engine的数据组织append-only特点 , 增量维护在Memtable , L0 , L1中 , 而基线数据维护在L2中;第2 , 维护增量时 , 采用双写 , 同时维护old-table和new-table中的数据 。 与InnoDB引擎类似 , 根据DDL是否涉及到数据记录格式变更 , 将DDL变更分为Inplace-rebuild和Inplace-norebuild两种类型 。 对于X-Engine来说 , 两者本质是一样的 , 区别在于维护的索引个数 。 Inplace-rebuild类型的DDL需要同时维护new-table中所有索引;而Inplace-norebuild类型的DDL只需要维护new-table的新增的索引 。