DM 分库分表 DDL “乐观协调” 模式介绍丨TiDB 工具分享

2024-04-08 02:08

本文主要是介绍DM 分库分表 DDL “乐观协调” 模式介绍丨TiDB 工具分享,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

DM 支持在线执行分库分表的 DDL 语句(通称 Sharding DDL),先前的文章中,我们介绍了悲观模式,即当上游一个分表执行某一 DDL 后,这个分表的迁移会暂停,等待其他所有分表都执行了同样的 DDL 才在下游执行该 DDL 并继续数据迁移。

悲观协调模式的优点是可以保证迁移到下游的数据不会出错,并且能兼容大部分的 DDL 语句,缺点是会暂停数据迁移而不利于对上游进行灰度变更、并显著地增加增量数据复制的延迟。有些客户可能会花数个月在单一分片执行 DDL,满意后才会更改其他分片的结构。在悲观同步的设定下,用来测试的分片的 DML 事件会大量积压,在恢复同步后无法正常运作。与此同时,悲观模式还要求所有分片必须以相同的顺序执行 DDL,否则会导致任务报错暂停。

为此,DM 提供新的乐观协调模式,在一个分表上执行的 DDL,自动修改成兼容其他分表的 DDL 语句后立即应用到下游,不会阻挡任何分表执行的 DML 的迁移。乐观协调模式适用于上游灰度更新、发布的场景,或者是对上游数据库表结构变更过程中同步延迟比较敏感的场景。

1.png

悲观协调和乐观协调的对比

原理

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

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

2.png

(具体的设计可以参考 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

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

如初始时表结构是相同的。

3.png

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

4.png

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

5.png

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

6.png

tbl1 重命名第二列。现在 tbl1 和 tbl2 的第二列名字不一样,无法比较,DM 无法确定最终的表结构,所以任务会报错

7.png

例子

三个分片合并同步到 TiDB

8.png

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

9.png

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;

10.png

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

11.png

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

12.png

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

此时下游已经有相同的 Level 列了,所以 DM master 比较之后不做任何动作。

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

13.png

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;

14.png

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

15.png

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

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

16.png

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

到此步 Name 列也从所有分片消失了,所以可以安全从下游移除。
alter table tbl drop column Name;

17.png

限制

使用“乐观协调”模式有一定的风险,需要严格遵照以下方针:

  • 执行每个批次的 DDL 前和后,要确保每个分表的结构达成一致。
  • 进行灰度 DDL 时,最好只集中在一个分表上测试。
  • 灰度完成后,在其他分表上尽量以最简单直接的 DDL 迁移到最终的 schema,而不要重新执行灰度测试中对或错的每一步。
  • 例如:在分表执行过 ADD COLUMN A INT; DROP COLUMN A; ADD COLUMN A FLOAT;,在其他分表直接执行 ADD COLUMN A FLOAT 即可,不需要三条 DDL 都执行一遍。
  • 执行 DDL 时要注意观察 DM 迁移状态。当迁移报错时,需要判断这个批次的 DDL 是否会造成数据不一致。

更详细的介绍可参考官网文档

这篇关于DM 分库分表 DDL “乐观协调” 模式介绍丨TiDB 工具分享的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/884298

相关文章

Java数字转换工具类NumberUtil的使用

《Java数字转换工具类NumberUtil的使用》NumberUtil是一个功能强大的Java工具类,用于处理数字的各种操作,包括数值运算、格式化、随机数生成和数值判断,下面就来介绍一下Number... 目录一、NumberUtil类概述二、主要功能介绍1. 数值运算2. 格式化3. 数值判断4. 随机

linux进程D状态的解决思路分享

《linux进程D状态的解决思路分享》在Linux系统中,进程在内核模式下等待I/O完成时会进入不间断睡眠状态(D状态),这种状态下,进程无法通过普通方式被杀死,本文通过实验模拟了这种状态,并分析了如... 目录1. 问题描述2. 问题分析3. 实验模拟3.1 使用losetup创建一个卷作为pv的磁盘3.

使用Navicat工具比对两个数据库所有表结构的差异案例详解

《使用Navicat工具比对两个数据库所有表结构的差异案例详解》:本文主要介绍如何使用Navicat工具对比两个数据库test_old和test_new,并生成相应的DDLSQL语句,以便将te... 目录概要案例一、如图两个数据库test_old和test_new进行比较:二、开始比较总结概要公司存在多

MySQL8.2.0安装教程分享

《MySQL8.2.0安装教程分享》这篇文章详细介绍了如何在Windows系统上安装MySQL数据库软件,包括下载、安装、配置和设置环境变量的步骤... 目录mysql的安装图文1.python访问网址2javascript.点击3.进入Downloads向下滑动4.选择Community Server5.

Java实现状态模式的示例代码

《Java实现状态模式的示例代码》状态模式是一种行为型设计模式,允许对象根据其内部状态改变行为,本文主要介绍了Java实现状态模式的示例代码,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来... 目录一、简介1、定义2、状态模式的结构二、Java实现案例1、电灯开关状态案例2、番茄工作法状态案例

CentOS系统Maven安装教程分享

《CentOS系统Maven安装教程分享》本文介绍了如何在CentOS系统中安装Maven,并提供了一个简单的实际应用案例,安装Maven需要先安装Java和设置环境变量,Maven可以自动管理项目的... 目录准备工作下载并安装Maven常见问题及解决方法实际应用案例总结Maven是一个流行的项目管理工具

Java中基于注解的代码生成工具MapStruct映射使用详解

《Java中基于注解的代码生成工具MapStruct映射使用详解》MapStruct作为一个基于注解的代码生成工具,为我们提供了一种更加优雅、高效的解决方案,本文主要为大家介绍了它的具体使用,感兴趣... 目录介绍优缺点优点缺点核心注解及详细使用语法说明@Mapper@Mapping@Mappings@Co

10个Python自动化办公的脚本分享

《10个Python自动化办公的脚本分享》在日常办公中,我们常常会被繁琐、重复的任务占据大量时间,本文为大家分享了10个实用的Python自动化办公案例及源码,希望对大家有所帮助... 目录1. 批量处理 Excel 文件2. 自动发送邮件3. 批量重命名文件4. 数据清洗5. 生成 PPT6. 自动化测试

使用Python实现图片和base64转换工具

《使用Python实现图片和base64转换工具》这篇文章主要为大家详细介绍了如何使用Python中的base64模块编写一个工具,可以实现图片和Base64编码之间的转换,感兴趣的小伙伴可以了解下... 简介使用python的base64模块来实现图片和Base64编码之间的转换。可以将图片转换为Bas

使用Java实现一个解析CURL脚本小工具

《使用Java实现一个解析CURL脚本小工具》文章介绍了如何使用Java实现一个解析CURL脚本的工具,该工具可以将CURL脚本中的Header解析为KVMap结构,获取URL路径、请求类型,解析UR... 目录使用示例实现原理具体实现CurlParserUtilCurlEntityICurlHandler