共计 3056 个字符,预计需要花费 8 分钟才能阅读完成。
X-Engine 是阿里巴巴自研的存储引擎,作为阿里云 RDS MySQL 的一个可选引擎,除了主打高性能和低成本,还减少了不少惠及用户的新性能。本文将具体介绍 MySQL(X-Engine) 如何近乎刹时实现传统数据库须要数小时实现的 DDL 操作。
1. 数据库 DDL 操作面临的问题
互联网业务倒退迅速,利用模式频繁更改是常态。相应地,数据库拜访模式和 schema 也随之变动。DDL(Data Definition Language)是 SQL 的一类,次要作用是创立和更改数据的 schema 信息,最常见的操作包含:加减列、更改列类型、加减索引等。相熟 MySQL 的同学都晓得,在 8.0 以前,尽管 Online DDL 不阻塞其它 DML(Insert/Update/Delete)操作,但许多重要的 DDL 操作,如加列、减列等,仍旧须要期待数小时、甚至好几天工夫(根据数据量的大小)才会失效。更改列类型等操作甚至仍须要锁表执行,阻塞 DML 操作。
DDL 操作运行工夫长,占用系统资源,须要额定的磁盘空间(建设长期表),影响零碎吞吐,并且一旦 DDL 过程中实例 crash,复原工夫也会很久。以加列 DDL 为例,MySQL 经验如下过程:
1. 以新 schema 建设空表。2. 拷贝数据到新表,并且将新加列的值赋为默认值,同时更新索引表。数据库承受到的 DML 操作被记录在临时文件。3. 加 exclusive lock,阻塞写操作,将临时文件记录的 DML 操作 apply 到新表。如果 DML 很多,这一阶段将破费较多工夫。4. 删除旧表,将新表命名为旧表的名字。
显然,这个过程加锁工夫长,拷贝数据操作会占用系统资源和长期空间,并须要大量 I /O。为了适应变动频繁的业务,不立刻更改存储层数据、能够疾速实现的 DDL(咱们称之为 Fast DDL)成为了一个必要 feature。MySQL 8.0 减少了 instant add column 性能,能够在短时间内只批改 table 元信息,实现加列操作。遗憾的是,它还不反对其它类型的 DDL。得益于阿里自研的存储引擎 X -Engine 存储了多版本 Table Schema,每一行记录在引擎层就实现了解析,并且能够根据更新版本的 schema 实现格局转换,X-Engine 因而可反对多种类型的 Fast DDL。
2. 业界 Fast ddl 实现计划
MySQL 8.0
record 记录了列个数, instant add column 操作只批改零碎表。
写操作:新格局的记录。
读操作:依据存储在零碎表中 default value 补齐新加列。
反对类型:
• Change index optionRename table
• Set/drop default
• Modify column when the table is empty
• Add/drop virtual columnsAdd columns
MariaDB10.3
整体实现计划与 MySQL8.0 相似,record 记录了列个数,在 leftmost leaf page 中记录所有列的 default 值.
反对类型:
• Add column
• Drop column
• Extend VARCHAR maximum(Only if the physical format allows; not VARCHAR(255) to VARCHAR(256))
Aurora
产生 ddl 后,更新零碎表,新、旧版本的 schema 均要记录下来。而后播送该批改。之后承受 DML 申请,首先转换相干 leaf page 的所有记录,而后执行 DML。
select 申请会将旧版本的记录拼接成新版本记录。
反对类型
• only supports adding nullable columns, without default values
3.X-Engine 多版本 schema
顾名思义,Fast DDL 指数据库可能在极短的工夫内实现用户收回的 DDL 指令并返回。之所以这么快,是因为只修零碎表里的元数据,不变更引擎层存储的数据。其实现的关键在于:元信息变更之后,内存、磁盘中的物理记录该如何解析。
Engine 的架构采纳了 LSM-Tree 的思维,将新写入的数据以追加形式写入内存 memtable,memtable 到肯定大小后 switch 为 immutable memtable,不再批改。而后逐步以固定大小 extent 的模式,flush 到长久化存储中。当 extent 到肯定数量后,通过合并 (Compaction) 操作,将雷同 Key 的多个版本合并。为了让每行记录可解析,最直观简略的计划便是将元信息附着在记录下面。为了可能不依赖零碎表解析记录,X-Engine 存储了较为具体的元数据,如果为每一行都附着一份,会占用大量的空间。为了大大减少存储老本,咱们保障每个 memtable 和 extent 外部的数据 schema 统一,并将 schema 信息存储在 memtable 和 extent 之上。
schema 信息蕴含了诸如列个数、列类型、列长度、默认值等要害信息。利用这些信息,X-Engine 能够在返回后果之前,实现列解析,并只需返回查问指标列的对应后果。上面给出了一个具体的例子,同一张表存在不同 schema 版本的 extent 时,如何返回后果。
4.X-Engine fast ddl 实现
当 MySQL 接管到一条 fast ddl 语句时,更新相干零碎表及元数据,新版本的表构造随之失效,这时这条 DDL 语句就执行胜利啦!到当初为止 X -Engine 存储的信息没有产生任何变动。
读申请
当零碎接管到 Select 申请时,MySQL 会将申请自身,连同以后最新版本 schema 信息(称之为 target schema)传递到 X -Engine。X-Engine 首先定位到记录的地位(某个 memtable 或 extent),并取相应数据 schema 解析记录失去初步后果。接着,比照数据 schema 和 target schema,对初步后果做适当填充、删减或批改失去最终后果返回。
X-Engine schema 更新
Fast DDL 命令执行胜利,新版本的 schema 失效,X-Engine 还对此无感知。当接管到第一条针对该表的 DML(Insert/Update/ Delete)请后,如果发现 X -Engine 的沉闷 memtable 的 schema 版本落后于最新版本,会触发 switch memtable 行为:解冻以后沉闷 memtable,产生新沉闷 memtable,将新 schema 赋予新沉闷 memtable。为了保证数据的正确性,该操作会期待所有正在进行的写事务实现后再执行。
写申请
每个写事务可能波及到 n(n>=1)个表。事务在提交时,须要在写入沉闷 memtable 之前判断:事务写入数据的 schema 版本是否与沉闷 memtable 的 schema 版本统一,如果不统一则应该报错退出,揭示用户重试。
Flush/Compaction
内存中 memtable 数量到肯定个数时会触发 Flush 操作,被选中 memtable 的数据以 extent 的模式写入磁盘,schema 也随之由 memtable 传递到 extent。Compaction 操作会合并多个 extent,如果参加同一工作的 extent schema 版本不统一,X-Engine 会以其中最新版本为准,生成新 extent。
总结
Fast DDL 能够解决很多利用的痛点,加列、扩大列的罕用的操作不必再须要漫长的期待。技术上,X-Engine 通过存储具体的多版本 schema 信息,不仅无需借助零碎表解析记录,而且能够轻易地实现不同版本 schema 之间的数据转换,进而能够反对丰盛的 Fast DDL 类型。