OceanBase V4 技术解读:从Alter Table 看DDL的支持

news2024/9/20 6:09:43

背景

数据库类型可以划分为两大类:关系型数据库和非关系型数据库。而关系型数据库以表格形式进行数据组织,同时遵循表关系的约束,例如创建一张表,表里面包含多个列,不同的列可以有不同的类型。当需要改表结构,如创建索引、修改主键、加减列操作、重分区等,这些操作统称为 DDL。OceanBase 支持多种DDL操作,以满足用户在实际生产环境中的需求。那么 DDL 的具体表现形式是什么,其实现的原理是什么?

这篇文章将从执行 alter table 的视角,来剖析OceanBase  DDL 语句的背后原理。特此说明,以下内容仅针对 OceanBase 4.x 发行版本。

DDL 流程

我们以一条修改列类型的 SQL 来开启 DDL 原理的探索,一起看下这条 SQL 语句的背后到底发生了什么,假设我们的表名为 t1,表结构里有 c1 列,原列类型为 int,我们执行如下的 DDL 操作。

alter table t1 modify column c1 bigint;

当用户执行了上述 SQL 后,如果我们部署了 OBProxy 的集群,SQL 指令会先发送到 OBProxy 中处理,然后 OBProxy 经过简单的解析,路由计算,把这条 SQL 发送到集群中的一台 OBserver,我们称为中控 OBServer。中控 OBServer 在收到消息后,经过 SQL 语法语义解析,发现这是一条 alter table 的 DDL 语句,在经过优化器、执行器以及生成物理计划后,通过 RPC 转发给另外一台 RootService(RS) 所在的 OBServer 节点来处理。当 RS 接收到来自中控 OBServer 的 RPC 请求后,从请求包里解析出需要修改的 Schema 表结构信息,并把这些信息更新到对应的内部表,然后再发起一个 DDL Task 任务,最后任务会被相关的 OBServer 节点执行。当任务执行完后,RS 会把任务状态发送回中控 OBServer 节点。特别的,对于执行时间可能比较长的 DDL 操作,RS 会识别出来并在任务创建后,返回任务 ID 给中控 OBServer,然后中控 OBServer 通过轮询任务状态,来决定什么时候结束返回。最后中控 OBServer 会把任务状态回给 OBProxy,OBProxy 再返回给客户端,结束本次 DDL 操作。我们来看下流程:

1698134937

Alter table

了解了 DDL 的执行流程之后,我们再来看下 alter table 内部触发了哪些具体操作。

当 RS 收到中控 OBServer 发送的请求包后,就已经知道这是一条修改列类型的 DDL。RS 经过一番计算后,发现这个修改列类型的 DDL 是 Offline DDL,需要对目标表的数据进行重整,于是 RS 结合解析出来的信息,创建出一个 DDL Task,并把这个 Task 放入到一个任务队列,我们叫 DDL Task Queue。后续会通过 DDL 任务调度(DDL Scheduler )从任务队列中得到这个 Task,执行完成后,把执行结果记录到内部表,最后中控 OBServer 从内部表中获取实时的执行状态,判断是否需要结束。我们看下简易流程:

1698134974

这里面的 DDL Scheduler 调度器工作最为繁重,因为要不停的从 DDL Task Queue 里取出任务并执行。

可能就有同学会问,如果我的一个 DDL 任务耗时很长,会不会阻塞调度器对其他任务的执行呢?答案是不会。这里我补充说明下,首先,DDL Scheduler 执行线程不止一个。其次,每一个 DDL 任务会被切分为多个任务状态来分段执行,DDL Scheduler 每调度一次,完成一次状态切换。DDL Scheduler 依赖这些状态的切换来推进任务,直到成功走到最后 Succ 成功的状态。

那如果在某个任务状态卡住了怎么办?这个问题问得太好了,我们会通过 DDL 重试机制来容错,一般一个 DDL 任务会设定 72h 的超时时间,如果确实是因为数据量比较大,在 DDL 补数据阶段需要的时间比较长,这种只能等待补数据结束,其他场景如获取 Table Entry 失败,或者获取锁冲突等异常,我们会做重试,根据经验 72 个小时足够容错。

那如果正在执行 DDL 的 RS 发生切主了,旧主的任务队列内存信息没有了,要怎么恢复呢?这很好解决,我们已经考虑到故障重启/切主等场景,RS 在创建 DDL Task 任务的同时,我们会把 DDL 任务状态持久化到内部表,切主后从内部表恢复任务状态,继续从上一个状态执行。

DDL 任务状态及演进

好了,既然 OceanBase 是根据状态机来推进 DDL 任务的,那么我们一起来看下修改列类型时,主要的任务状态含义以及演进过程吧:

1698135001

Wait_trans_end

等事务结束。这里补充说明下,OceanBase 在做列类型转换的 DDL 时,是通过双表双写的方式进行的,即按照 DDL 后的表结构 Schema 创建一张新的隐藏表,并把旧表的数据全部切换到新隐藏表里。但因为创建表之后可能还有一些 DDL 操作前的事务还没结束,因此需要等待这些事务结束,并获取一个全局快照点,来做后续的操作。

Obtain_snapshot

获取快照点。在上面等事务结束后,我们获取一个全局快照点,这个快照点是新表从旧表中重写数据的依据。此时,只要对快照点之前的数据进行补全就能保证新表的数据是完整的。需要进一步说明的是,在快照点之前也有一些事务已经往新表里插入过数据,但根据幂等性,我们可以保证读出来的数据没有问题。

Redefinition

补数据。在上面的状态结束后,我们得到了一个全局快照点,并且因为这是一个修改列类型的 DDL,我们假设修改的列非主键列,不涉及分区键的变更,因此修改后的列相关的宏块是不需要重新排序的。这里应该很好理解,分区键未变化,修改后新表的分区和原表的分区规则相同,在分区键不变的情况下,新表数据分区位置不变。为了会更好的理解补数据的逻辑,下面稍微展开介绍下补数据的类别。

补全数据分为三类:

  • 第一类是需要分区排序,但源表和目的表分区规则不同,如创建全局索引。排序是指将主表分区之间的数据做排序后,填充到全局索引表。
  • 第二类是需要分区排序,但源表和目的表分区规则相同,如修改主键、创建局部索引。这个应该很好理解,修改主键和创建局部索引不会变更新旧表的分区方式,但会影响分区内数据的顺序,排序是指数据重新排列后,填充到新表分区。
  • 第三类是分区内不需要排序,例如,修改列类型(假设是未修改主键列的列类型)。这就更好理解了,因为主键(rowkey)不变,修改列类型不会影响数据在存储中的顺序,因此不需要重新排序。

为了更加直观查看数据的分区排序,我们举例创建全局索引的补数据过程吧:

1698135021

Copy_table_dependent_object

重建与原表相关的对象以及约束。例如索引表,在上面的例子中,我们修改了列类型,假设这个列是索引表中的列,那么索引表同样需要被重建,也需要 RS 创建一个重建任务,主体流程和主表 DDL 类似。

Take_effect

新表生效。在做完上面的补数据流程后,我们认为新表已经具备了完整的数据,并且可以对外提供服务了。由于在整个补数据阶段我们是锁表的,也就是屏蔽了 DML/DDL 的并发干扰,因此只需要把新表的名字直接切换成旧表的名字即可。在这之后还会做一些收尾的动作,例如恢复分区读写、删除原表、清理临时数据等。

Online 和 Offline

上面提到 Online 和 Offline 这些个字样,我在这里简单补充说明一下。由于 OceanBase 采用 Offline DDL 双表双写方式,涉及隐藏表的创建以及对主表数据的重整,即需要把数据写入到新表,表数据越多,执行时间越长。Offline 的意思是说,在执行 DDL 的同时,会阻塞其他 DML 的操作。实现的原理其实也简单,给需要做 DDL 的表加上一把表锁,当 DML 执行需要获取这把锁时,发现已经被其他事务持有,那么就会等待重试直至超时退出。与之相对应的是 Online DDL,也就是在 DDL 的同时,允许 DML 操作。实现上是 DDL 只修改表 Schema 原数据信息,例如修改表名,加列等操作,表结构完成修改后,其他事务可以立刻操作新表,源表数据不需要立刻做重整。

对于我们支持的 Online DDL 类型,同学们可以参考这篇文章:OceanBase 4.0解读:兼顾高效与透明,我们对DDL的设计与思考

写在最后

经过上面的介绍,相信同学们的心里已经对 OceanBase 的 alter table 流程有了大概的认识。当然,DDL 的场景还有很多,上面只是列举了列类型变更一种,或说一类操作吧(Offline DDL),希望能让同学们有个感性的认识。另外,OceanBase 的 DDL 的整体流程相对并不复杂,但因为往往需要和事务、RS、复制迁移等交互,以及需要控制 DDL 任务执行对 CPU、磁盘 IO 的影响,细节很多,内容还是相当丰富的。有兴趣的同学可以看下代码的具体实现细节,也欢迎在评论区和我们一起探讨。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2075735.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是数据库 DevOps?

在深入研究数据库 DevOps 之前,先回顾一下什么是 DevOps。它没有统一的定义,但我们知道它起源于软件开发方法与部署和运维的结合。 大约 2007 年和 2008 年,软件开发和 IT 界人士提出了这样的担忧:两个行业的分离,即编…

Datawhale X 李宏毅苹果书 AI夏令营(深度学习入门)task3

实践方法论 在应用机器学习算法时,实践方法论能够帮助我们更好地训练模型。如果在 Kaggle 上的结果不太好,虽然 Kaggle 上呈现的是测试数据的结果,但要先检查训练数据的损失。看看模型在训练数据上面,有没有学起来,再…

解锁 TypeScript Record 的奇妙用法:轻松搞定键值对!

在没有非常了解 Record 之前,定义对象的类型,一般使用 interface。它是 TS 中定义数据结构的一种方式,用来描述对象的形状、函数类型、类的结构等。 // 基本用法 interface User {name: string;age: number;isAdmin: boolean; }const user: …

抖音ip地址与实际地址不符是怎么回事

在数字化时代,社交媒体已成为人们日常生活不可或缺的一部分,而抖音作为其中的佼佼者,更是吸引了数以亿计的用户。然而,在使用抖音的过程中,不少用户发现了一个有趣而又令人困惑的现象:抖音显示的IP地址与实…

趣味算法------煤球数目

目录 前言: 题目描述: 解题思路: 具体代码: 前言: 数列在数学中是一个非常基础且重要的概念,它指的是按照一定顺序排列的一系列数。数列中的每一个数被称为该数列的项。 数列可以分为有限数列和无限数列…

7 nestjs 环境变量

安装 pnpm i --save nestjs/confignestjs/config 内部使用 dotenv 实现。 配置 一般会在根模块AppModal中导入,并使用.forRoot()静态方法导入它的配置 import { Module } from nestjs/common; import { ConfigModule } from nestjs/config; ​ Module({imports: …

降低游戏直播软件开发风险:自建团队、外包公司与现成源码

随着游戏直播行业的快速发展,越来越多的企业和个人开始涉足这一领域。然而,在游戏直播软件的开发过程中,选择合适的开发模式对于降低供应链风险至关重要。本文将探讨三种主要的游戏直播软件开发模式,并分析它们各自的风险管理策略…

设计模式篇(行为型模式 - DesignPattern)(持续更新迭代)(图片待加载)

目录 一、模版方法模式(制作豆浆问题) 1. 豆浆制作问题 2. 模板方法模式 2.1. 基本介绍 2.2. 代码实现 2.3. 钩子方法 2.4. 应用案例 应用一:Android中View的draw 应用二:Spring 框架应用的源码分析 2.5. 注意事项和细节…

泰国中小企业局局长率考察团到访深兰科技

继泰国社会发展和人类安全部考察团的访问之后,深兰科技本周迎来了第二波泰国政府考察团的莅临。 2024年8月23日,泰国中小企业促进局局长巴尼塔西那瓦女士率领泰国东盟企业家协会、泰国法政大学及泰国企业家代表团访问了深兰科技集团总部。深兰科技集团董…

卡牌抽卡机小程序搭建,探索新鲜有趣的拆卡体验

卡牌作为一种新的潮玩方式,市场热度逐渐提升,在各大社交平台上,拆卡的话题层出不穷,各种卡牌迅速走红,成为了当下“顶流”,吸引了众多的消费者!卡牌的价格低,还涉及到了动漫等各个热…

电商行业为什么要做私域?

有伙伴提到,他们所在的电商企业是否有必要进行私域运营,担心投入太大。 实际上,私域运营对于电商企业来说是非常有必要的。它是企业的用户数据资产,关乎着企业未来的发展。私域运营能够帮助企业更好地了解用户需求,提…

Vulkan入门系列17 - 多重采样( Multisampling)

一:概述 我们的程序现在可以加载多个级别的纹理,从而解决了在渲染远离观察者的物体时出现的伪影问题。现在图像变得平滑多了,但仔细观察,你会发现绘制的几何图形边缘呈现锯齿状。这在我们早期渲染一个四边形的程序中尤为明显: 这种不希望有的效果被称为 “锯齿”,…

2024高质量:备战金九银十的Java八股文+场景题,看完这篇就够了!

前言 又到一年金九银十面试跳槽季,你准备好了吗? 今天为大家整理了目前互联网出现率最高的大厂面试题,所谓八股文也就是指文章的八个部分,文体有固定格式:由破题、承题、起讲、入题、起股、中股、后股、束股八部分组成&#xff0…

Python 数据分析之Numpy学习(二)

Python 数据分析之Numpy学习(二) 接上文:Python 数据分析之Numpy学习(一) 四、数组的索引和切片 索引即通过一个无符号整数值获取数组里的值。Python索引是从0的位置开始。 切片即对数组里某个片段的描述。 # 载入…

虚幻5|制作玩家血量,体力(还未编辑,只用于引用)

未编写,仅引用 优化后: 把增加生命,减少生命,也可以用在体力里,更改如下 限制浮点,如果血量或体力按10来扣,如果你的血量降低到5,那么就会以5的数值来扣,而不会扣成-5…

如何在路由器中抓包分析

方法是在openwrt中一般都集成了tcpdump抓包工具,可以通过命令抓包保存为pcap文件,导出来后可以通过wireshark分析。 相信大部分研发人员都在windows下抓过包,最常用的软件就是wireshark,通过wireshark可以很方便的分析数据报文。抓…

理解运营商和全球网络

目录 理解运营商和全球网络 如何上网 光纤入户 购买设备 配置网络 互联网的发展 引入 国家推动 理解运营商和全球网络 如何上网 光纤入户 也就是俗称的拉网线 将光纤宽带服务直接连接到你家中 光纤是由运营商提供 通过玻璃丝传递光电信号,传进来变成模拟信号,再由调制…

【计算机网络】socket网络编程 --- 实现一些简易UDP网络程序

👦个人主页:Weraphael ✍🏻作者简介:目前正在学习c和算法 ✈️专栏:Linux 🐋 希望大家多多支持,咱一起进步!😁 如果文章有啥瑕疵,希望大佬指点一二 如果文章对…

笔记整理—uboot启动过程(6)env_init与init_sequence总结

上一章说到uboot的BL2部分板级初始化,这一章将继续对uboot的环境变量初始化内容进行说明。 env_init,顾名思义这是与环境变量相关的初始化。env_init有许多个,因为uboot支持不同的启动介质(不同的芯片或开发板)。其中i…

Android - 音频参数合入

音频参数宏观来看分为两部分,audio和music。不管是哪个平台都需要分别合入这两部分。 A10 music参数 相关工程师调试后会提供 audio_para 文件,将该文件替换至对应工程下的文件编译即可 例: device/sprd/sharkle/sl8541e_1h10_32b/rootdir/system/et…