乐趣区

关于数据库:DM-分库分表-DDL-乐观协调-模式介绍丨TiDB-工具分享

前言

DM 反对在线执行分库分表的 DDL 语句(通称 Sharding DDL),先前的文章中,咱们介绍了乐观模式,即当上游一个分表执行某一 DDL 后,这个分表的迁徙会暂停,期待其余所有分表都执行了同样的 DDL 才在上游执行该 DDL 并持续数据迁徙。

乐观协调模式的长处是能够保障迁徙到上游的数据不会出错,并且能兼容大部分的 DDL 语句,毛病是会暂停数据迁徙而不利于对上游进行灰度变更、并显著地减少增量数据复制的提早。有些客户可能会花数个月在繁多分片执行 DDL,称心后才会更改其余分片的构造。在乐观同步的设定下,用来测试的分片的 DML 事件会大量积压,在复原同步后无奈失常运作。与此同时,乐观模式还要求所有分片必须以雷同的程序执行 DDL,否则会导致工作报错暂停。

为此,DM 提供新的乐观协调模式,在一个分表上执行的 DDL,主动批改成兼容其余分表的 DDL 语句后立刻利用到上游,不会阻挡任何分表执行的 DML 的迁徙。乐观协调模式实用于上游灰度更新、公布的场景,或者是对上游数据库表构造变更过程中同步提早比拟敏感的场景。


<center> 乐观协调和乐观协调的比照 <center>

原理

DM worker 的所有 DML 会间接同步到上游(出错时例外)。

DM worker 内嵌了一个小型 TiDB(通称 schema tracker),用来记录各个上游分表的表构造,当接管到来自上游的 DDL 后,会依据 schema tracker 里 DDL 的执行后果,把更新后的表构造转送给 DM master。DM master 将收到的不同分片的表构造合并成可兼容所有分片的 DML 的合成构造,即不同分片表构造的并集(此过程相似于 SQL 语句中的 JOIN 语句),而后依据合成的表构造和 DM worker 发来的表构造的不同处失去对应的 DDL 语句(即合成的表构造与原表构造的差集),同步到上游。

(具体的设计能够参考 [DM: Manage DDLs on Sharded Tables by Maximizing Schema Compatibility]

规定

乐观 DDL 表构造合并的规定简略来说就是对列属性定义了一个 偏序关系,对不同表的同一列进行排序,抉择该偏序关系中的极大元。对于不可比拟的列,则返回谬误

  • null < not null
  • no default < default(x)
  • varchar(x) < varchar(y), where x< y
  • utf8 < utf8mb4
  • char < varchar
  • tinyint < smallint < mediumint < bigint

对于被不存在或者被删除的列,咱们把它定为最小的列

如初始时表构造是雷同的。

tbl2 增加第三列。前两列雷同;tbl1 的第三列为空,所以保留 tbl2 的第三列。

tbl2 删除第一列。第二列雷同;tbl2 的第一列为空,所以保留 tbl1 的第一列。tbl1 的第三列为空,所以保留 tbl2 的第三列

tbl1 将第二列改为 varchar(10),因为 varchar(5) < varchar(10),所以保留 tbl1 的第二列

tbl1 重命名第二列。当初 tbl1 和 tbl2 的第二列名字不一样,无奈比拟,DM 无奈确定最终的表构造,所以工作会报错

例子

三个分片合并同步到 TiDB

① 在上游减少一列 Level。
alter table tbl00 add column Level int unsigned not null;

tbl00, tbl01, tbl02 的并集 tblMerge 是 {ID,NAME,Level}
tblMerge 和 tbl 的差集是 {Level},所以 DDL 是 add column Level

此时上游 TiDB 要筹备承受来自 tbl00 有 Level 的 DML、以及来自 tbl01 和 tbl02 没有 Level 的 DML,所以同步到上游时,主动改写成指定默认值的模式。
alter table tbl add column Level int unsigned not null default 0;

这时候各种 DML 毋需批改都能够同步到上游。
update tbl00 set Level = 9 where ID = 1;
insert into tbl02 (ID, Name) values (27, ‘Tony’);

② 在 tbl01 同样减少一列 Level。
alter table tbl01 add column Level int unsigned not null;

tbl00, tbl01, tbl02 的并集 tblMerge 是 {ID,NAME,Level}
tblMerge 和 tbl 的差集是 {},所以 DDL 为空

此时上游曾经有雷同的 Level 列了,所以 DM master 比拟之后不做任何动作。

③ 在 tbl01 刪除一列 Name。
alter table tbl01 drop column Name;

tbl00, tbl01, tbl02 的并集 tblMerge 是 {ID,NAME,Level}
tblMerge 和 tbl 的差集是 {Level},所以 DDL 为空

此时上游仍须要接管来自 tbl00 和 tbl02 含 Name 的 DMLs,故不立删之,而是为这列也补上一个默认值。
alter table tbl alter column Name set default“”;

同样,各种 DML 仍可间接同步到上游。
insert into tbl01 (ID, Level) values (15, 7);
update tbl00 set Level = 5 where ID = 5;

④ 在 tbl02 减少一列 Level。
tbl00, tbl01, tbl02 的并集 tblMerge 是 {ID,NAME,Level}
tblMerge 和 tbl 的差集是 {Level},所以 DDL 为空
alter table tbl02 add column Level int unsigned not null;

此时所有分片都已有 Level 列,所以能够把作为兼容的默认值去掉。
alter table tbl alter column Level drop default;

⑤⑥ 在 tbl00 和 tbl02 各刪除一列 Name。
alter table tbl00 drop column Name;
alter table tbl02 drop column Name;

tbl00, tbl01, tbl02 的并集 tblMerge 是 {ID,Level}
tblMerge 和 tbl 的差集是 -{Name},此差集是有符号的,所以 DDL 是 drop column Name

到此步 Name 列也从所有分片隐没了,所以能够平安从上游移除。
alter table tbl drop column Name;

限度

应用“乐观协调”模式有肯定的危险,须要严格遵循以下方针:

  • 执行每个批次的 DDL 前和后,要确保每个分表的构造达成统一。
  • 进行灰度 DDL 时,最好只集中在一个分表上测试。
  • 灰度实现后,在其余分表上尽量以最简略间接的 DDL 迁徙到最终的 schema,而不要从新执行灰度测试中对或错的每一步。

    • 例如:在分表执行过 ADD COLUMN A INT; DROP COLUMN A; ADD COLUMN A FLOAT;,在其余分表间接执行 ADD COLUMN A FLOAT 即可,不须要三条 DDL 都执行一遍。
  • 执行 DDL 时要留神察看 DM 迁徙状态。当迁徙报错时,须要判断这个批次的 DDL 是否会造成数据不统一。

更具体的介绍可参考官网文档

退出移动版