MySQL 8.0.29 instant DDL 数据腐化问题分析

news2024/9/24 23:30:00
  • 前言
  • Instant add or drop column的主线逻辑
  • 表定义的列顺序与row 存储列顺序阐述
  • 引入row版本的必要性
  • 数据腐化问题
  • 原因分析
  • Bug重现与解析
  • MySQL8.0.30修复方案

前言

DDL 相对于数据库的 DML 之类的其他操作,相对来说是比较耗时、相对重型的操作; 因此对业务的影比较严重。MySQL 从5.6版本开始一直在持续改进其DDL性能:引入了 online DDL,inplace DDL,instant DDL 等实用性极强的功能, DDL 目前对业务的影响持续降低。

MySQL 8.0.29 引入了 instant add/drop column 功能,支持在任意位置添加 column, drop column 也不需要表数据的任何形式的移动, 只需要修改表的元数据就可以完成 add/drop column,所以 instant add/drop column 的操作是轻型操作,速度快,资源需求量少。

ALTER table drop column a, ALGORITHM=INSTANT;

8.0.29 引入了新的alter 算法 INSTANT。

但是这个新功能目前很不稳定,导致的问题比较多; 而且通常都比较严重: 数据损坏,或者数据库无法启动等。

本文是分析其中的一个问题: 对表进行 instant drop 后,进行 update ,之后数据库停机,而后数据库无法启动。

为分析这个问题, 我们会从 instant add/drop column 在 Innodb 的实现原理与细节方面来阐述这个数据腐化bug的具体原因。

Instant add or drop column的主线逻辑

因为这个功能的WorkLog无法从官方获取,所以无法得到准确的设计出发点,通过阅读相关代码,得出要实现这个功能,必须要处理以下关键点:

  • 因为要支持在任意位置添加/删除列,同时不会更改表数据文件,所以表的逻辑定义与row的实际存储形式需要映射关系,不再是所见即所得的一一对应的关系。即为了实现这样功能:

    • 表中列的定义顺序与表中行数据(row)的存储顺序是不同的。
    • 同时对同一个table可以做多次instant DDL, 所以需要引入版本机制,在表的数据文件中,不同row对应的表定义可能是不同的,需要在row中记住表定义的version。

以上可以认为是该功能的设计原则与实现的主线逻辑。

表定义的列顺序与row 存储列顺序阐述

在引入这个功能之前, create table 时列定义的顺序与列在 InnoDB 中存储的顺序是一致的。(这里我们不用考虑 InnoDB 添加系统隐藏列)

Instant add/drop column 要实现的亮点功能是在表定义的任意位置添加或者减少 column,同时做这样的操作的时候,能够做到不需要重构表数据。

我们称 column 在表定义中出现的顺序为逻辑顺序;

而 column 在行数据的存储顺序为物理顺序

要做到修改表定义,而不重构表数据,就必须将逻辑顺序与物理顺序解耦: 不能再像MySQL 8.0.29之前的版本那样,逻辑顺序与物理顺序是完全一致的;而从8.0.29开始通过表的元数据保存了逻辑顺序与物理顺序的映射关系。这种映射关系的构建与维护构成了 instant add/drop column 的基础.

如下图简单阐述了逻辑/物理顺序的关系。

image-20230612135907422

引入row版本的必要性

对于同一张表,Instant add/drop DDL可以执行多次;每一次执行后,逻辑/物理顺序的映射关系就发生变化;同时 instant add/drop DDL 并不需要做表数据的重构操作;因此可以得出经过多次 instant add/drop DDL,InnoDB存储的行数据与表定义存在多种逻辑/物理顺序映射关系:比如说,在 ibd 文件中,前十行数据对应原始的表定义,接下来的十行可能对应着 instant add column 后的数据,再接下来的十行,可能对应着 instant drop column 后的数据。

为了管理这种形式的逻辑/物理,在 InnoDB 中,为每一行实际存储的数据引入了版本号的概念:每个版本号对应着一个逻辑/物理映射关系。

为存储这个版本信息,InnoDB 中,row 的信息头记录的格式有稍微的变化:

图片

如上图所示,在row的extra中存储了其对应的版本号, 同时在 row header 中有标志位指示出了是否存在版本号信息。

根据版本号获取相应的映射关系,就可以正确的解析行数据。

目前版本号最大支持到64, instant add/drop column 到达这个限制后报错;其后如果还需要 instant add/drop column DDL 操作,可能需要做一次能够触发 table rebuild 操作才可以。

数据腐化问题

由 instant add/drop column 引入了多个数据腐化问题,其中一个问题可以从:

[PS-8292] MySQL 8.0.29 fails to perform crash recovery - Percona JIRA(https://jira.percona.com/browse/PS-8292) 查看。

这个问题简单来说:在对表进行 instant drop 后,进行update操作,之后MySQL server 重启,在启动阶段恢复之前的 update 操作会引发 assert 崩溃(debug版本的情况下)。

从代码上看,这个bug可能会造成数据的静默错误(数据完全错乱而且不报任何错误),而不仅仅是崩溃这一种现象。

通过对core文件的简单分析,造成该问题的大概原因如下:

在通过redo做恢复的时候,字段的逻辑顺序与物理存储顺序之间的映射关系不对(错位)导致的。在恢复期间可能会找不到对应的字段,或者更新了错误的字段

原因分析

从原始的问题看,这个是发生在 InnoDB 启动恢复阶段。这一阶段离不开 redo log的参与。前面介绍 instant add/drop 设计要点的时候,那些列出的要点,可以认为是在在 DDL 期间的工作以及编码的基本逻辑;那么在完成 instant DDL 时候, 在 DML 的时候也需要将必要的信息写入 redo log 才能做到 recovery。

  • 为支持 instant add/drop column,redo log 记录的格式发生了变化,因为代码bug,导致在解析 redo log 做恢复的时候,得到的字段信息错误,导致数据腐化。
  • 问题表现出来可能是: 恢复始终无法执行,数据库无法启动;还可能是恢复到错误的数据,数据库能够启动。

因为 redo log 的种类较多,信息也比较繁杂,这里我们只关注问题本身中出现的 update 相关的 redo log ,进而较多的关注 update redo log 与该问题相关的字段信息。

下图简要的阐述了 update redo log 相关内容:

图片

到这里,可以看到 在MySQL 8.0.29中,update redo log 引入了 instant column 的物理逻辑顺序。

下面从 InnoDB 的恢复流程跟踪问题发生的原因,其中主要需要关注的是恢复过程中的表(索引)定义。

  • 应用 redo log 是在数据库启动阶段最开始就执行,此时数据字典无法打开,获取不到待恢复表的定义信息
  • 但是此时需要表的定义信息去解析 redo log 中的相关数据
  • 此时就会根据redo log中记录的长度信息,以及记录长度的顺序构建临时的表定义,此时仅仅是为了恢复,并不需要精确的表定义,此时只需要知道field的长度和位置即可。
  • 同时如果 redo log 中如果有instant DDL 的信息,那么也会用这些信息去修改临时构建的表定义:这是问题发生的初始错误的地方。
  • 恢复过程中,构建出的临时表实际上表中列的逻辑顺序,这是符合正常运行的需求的。
  • 但是实际上8.0.29中字段长度的记录顺序是按字段(列)的物理存储顺序写入的。
  • 如果带有 instant DDL 的信息,那么修改表定义时就会按物理顺序去修改逻辑顺序的表定义,这样会修改到非预期的字段,导致错误发生!

Bug重现与解析

CREATE TABLE `tb1` (
  `col1` VARCHAR(10) NOT NULL,
  `col2` char(13),
  `col3` varchar(11),
  PRIMARY KEY (`col1`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
INSERT INTO tb1  VALUES ('4000','50','100');
--echo # the FIRST INSTANT ALTER
ALTER TABLE tb1 DROP COLUMN col2, LOCK=DEFAULT;
INSERT INTO tb1  VALUES( '4545', '52' );
UPDATE tb1 SET col3 = '46' WHERE col1 = '4545';
--echo # crash and restart 1
--source include/kill_and_restart_mysqld.inc
CHECK TABLE tb1;
DROP TABLE tb1;

以上MySQL MTR 测例可以重现 InnoDB 启动恢复期间始终 core 的问题。我们从这个例子出发,结合上面解释的 instant drop DDL 代码行为看看问题是如何一步步发生的。

  1. 首先说明一下,在测例运行期间逻辑顺序与物理顺序的变化。 如下图所示稍微展示了 table 的逻辑定于与 InnoDB row 存储的以下细节。这里注意的是 被 dropped column 仍然会以隐藏列的形式存在于表定于中:因为 drop 之前存在的 row 还是需要这样信息解析字段。

图片

  1. 结合 redo log 的恢复过程看看问题发生的第一现场。这里针对这个测例摘取相关 redo log 的部分信息:

    图片

    2.1 按照字段长度列表(8.0.29中是物理顺序写入的列表)创建的专门用于恢复的表,类似于: create table dummy_table (d1:10, d2:13, d3:11)

    2.2 按照 instant 字段信息修改 dummy 表:按照 physical pos=1 去修改后,结果类似于:create table dummy_table (d1:10, d2:13[dropped], d3:11)

    2.3 期望的正确的表应该类似于:create table dummy_table(d1:10, d3:11, d2:13[dropped]);

    2.4 Redo log中的Field_no=1, 去恢复时期望用到的是 #2.3 的表,但是过程中创建的是#2.2中错误的表,这样当Field_no=1去恢复数据时,会错误的发现对应的field(column)已经dropped, 导致core!

MySQL8.0.30修复方案

知道了问题发生的原因,修复起来就比较简单了:

  • MySQL 8.0.30的代码修复方案

    • Redo log中字段的长度列表,按照字段的逻辑顺序写入,不再按存储顺序写入。
    • 在 redo log 的 instant column 信息中也包含了字段的逻辑位置。
    • Redo log 的记录本身的版本设置为 1 ,与8.0.29的版本为 0 ,做出差别。
    • 8.0.30的修复代码本身也是不能正确解析8.0.29产生的 redo log ,只是根据版本号检测出8.0.29 redo log,进而报错防止数据进一步恶化。实际上8.0.29的 redo log ,在 instant DDL 后,是不可能正确解析的,因为没有逻辑/物理的映射关系。
  • 修复的逻辑比较简单:

    • Redo log中字段的长度列表,按照字段的逻辑顺序写入:

      保证在恢复阶段构建的临时表是按正确的逻辑定义顺序构建的。

    • 在redo log 的 instant column 信息中也包含字段的逻辑位置:

      保证在更新临时表的字段时,按照逻辑顺序,不会出现错误更新的情况。

下面是MySQL 8.0.30 update redo log 相关字段信息:

图片

从上图可以看出,MySQL 8.0.30 redo log 中已经不存储物理位置相关的信息了,全部是逻辑位置相关的信息;这样就和MySQL 8.0.29 redo log 这种有问题的记录方式是昙花一现了。

附带的这个测例可以重现数据的静默错误(恢复过程没问题, 但是数据实际上错了)

CREATE TABLE `tb2` ( `c1` char(4) NOT NULL, `c2` char(4), `c3` char(4), PRIMARY KEY (`c1`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
begin;
INSERT INTO tb2  VALUES ('1000','2000','3000');
commit;
--echo # the FIRST INSTANT ALTER
ALTER TABLE tb2 add COLUMN c4 char(4) after c1, LOCK=DEFAULT;
INSERT INTO tb2 VALUES ('1001','4001', '2001', '3001');
SELECT * FROM tb2;
UPDATE tb2 set c4='4002' WHERE c1='1001';
--echo # crash and restart 1
--source include/kill_and_restart_mysqld.inc
select * from tb2;
CHECK TABLE tb2;

需要把这个测例放到innodb test case suite中。


Enjoy GreatSQL :)

关于 GreatSQL

GreatSQL是由万里数据库维护的MySQL分支,专注于提升MGR可靠性及性能,支持InnoDB并行查询特性,是适用于金融级应用的MySQL分支版本。

相关链接: GreatSQL社区 Gitee GitHub Bilibili

GreatSQL社区:

image

社区有奖建议反馈: https://greatsql.cn/thread-54-1-1.html

社区博客有奖征稿详情: https://greatsql.cn/thread-100-1-1.html

社区2022年度勋章获奖名单: https://greatsql.cn/thread-184-1-1.html

(对文章有疑问或者有独到见解都可以去社区官网提出或分享哦~)

技术交流:

image-20221030163217640

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

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

相关文章

ASO优化之关于应用宝的关键词排名

应用宝是国内主要的安卓应用分发渠道之一,它的流量和影响力是非常大的。所以我们可以通过ASO优化,来提升应用宝关键词覆盖和排名,从而有利于应用可以获得稳定的自然下载量。 关键词覆盖要围绕元数据的优化(包括应用名称&#xff…

ai智能写诗你了解吗?

在当今科技快速发展的时代,越来越多的人开始注重人工智能在日常生活中的应用。其中之一就是智能写诗软件,这种技术不仅可以为我们提供便捷的创作体验,还可以让我们轻松地享受到优美的诗歌韵律。那么,智能写诗软件怎么用呢&#xf…

服务端测试深度解析:如何保障后端稳定性

一、引言 在日益数字化的时代,软件稳定性和高可用性的保证对企业来说至关重要。在众多环节中,服务端作为整个系统的心脏,它的稳定性对用户体验和企业声誉影响尤为深远。因此,进行全面彻底的服务端测试具有重要意义。本文将深入讨…

真和思科有关?官方严令广东电信彻查网络故障!

下午好,我的网工朋友。 广东电信那事儿,大家都听说了吧,这闹的,行业内无人不晓了吧。 昨天晚上有聚餐,没来得及跟你们唠上这事儿,这会儿下班前,唠唠? 虽然昨晚已经恢复正常&#x…

工作4/5年,中高级测试工程师的我需要掌握什么?该往哪个方向发展?

毕业到公司4/5年,一般做软件测试至少是中级测试工程师了,好一些到高级测试工程师了。 我觉得对于中高级测试工程师的要求有几点 首先:你得有比较强的产品思维能力,你要知道产品的逻辑是什么,你要能站在用户的角度去思…

ArkTS语言HarmonyOS/OpenHarmony应用开发-message事件刷新卡片内容

开发过程 在卡片页面中可以通过postCardAction接口触发message事件拉起FormExtensionAbility,然后由FormExtensionAbility刷新卡片内容。 common:公共文件 通过点击button按钮,刷新卡片内容。代码示例: WidgetCard.ets let stor…

网页端兼容ie浏览器,强制用户以最高版本的ie进行页面渲染

1.针对浏览器&#xff0c;兼容不同ie版本写法 //IE9以及低于IE9版本 : <!--[if IE]><link rel"stylesheet" type"text/css" href"index.css" /> <![endif]-->//IE10或IE11: media all and (-ms-high-contrast: none), (-ms-h…

【JavaScript】实战训练小项目-WebAPI

JavaScript实战训练小项目 文章目录 JavaScript实战训练小项目 & WebAPI1. JS操作DOM树1.1 获得HTML控件/元素标签1.2 操纵控件1.2.1 获取属性值1.2.1 修改属性值 1.3 实现一个猜数字的功能 2. JQuery3. 简单计算器4. 聚合搜索5. 表白墙 JavaScript实战训练小项目 & We…

cuda编程入门07

程序优化技巧 程序解读 降低256倍&#xff0c;但是后面数组长度还是不知道的 对1万的元素在此降低一定倍数 初始加速比为9.58左右 这里没有volatie if (tid < 32) sdata[tid] sdata[tid 32];__syncthreads();在一个wrap内进行合并 sdata[tid] sdata[tid 32];sdata[ti…

【kali】使用VMware安装kali

目录 2、解压 3、安装 3.1 然后打开vm虚拟机&#xff0c;在文件菜单中选择打开 3.2 找到已解压的文件&#xff0c;选择一下文件 4、开启虚拟机&#xff0c;进入系统 1、下载 Get Kali | Kali Linux 我使用的是VMware12&#xff0c;所有下载下图 2、解压 3、安装 3.1 然后…

一文讲透彻!RobotFramwork测试框架教程(全能)

Robot Framwork在业界早已名声大振&#xff01;有很多刚学自动化测试的伙伴问我&#xff1a;有没有不需要编程就可以玩自动化的方法&#xff1f; 有吗&#xff1f;有的&#xff01;——Robot Framwork 我们今天就一篇文章&#xff0c;把它讲得明明白白&#xff01; 一、Robo…

使用php语言抓取网站商品详情代码及解析效果展示

抓取网站商品详情需要使用爬虫技术&#xff0c;可以使用 PHP 的 CURL 库来发送 HTTP 请求&#xff0c;然后解析 HTML 页面&#xff0c;获取商品详情信息。以下是一个简单的示例代码&#xff1a; <?php // 定义要抓取的商品 URL $url "https://example.com/produ…

华为OD机试 JavaScript 实现【密码强度等级】【牛客练习题】,附详细解题思路

一、题目描述 密码按如下规则进行计分&#xff0c;并根据不同的得分为密码进行安全等级划分。 1、密码长度&#xff1a; 5 分: 小于等于4 个字符 10 分: 5 到7 字符 25 分: 大于等于8 个字符 2、字母&#xff1a; 0 分: 没有字母 10 分: 密码里的字母全都是小&#xff08;…

执行修改方法返回值为0但是也没报错是什么原因

这篇文章仅仅记录 用springBoot加mybatis 搭建环境 一直没执行成功 百思不得其解 最后发现是controller中一个参数问题 一开始是这样 修改成这样就好了 数据库数据也能更新了 将param改成RequestParam 具体原因大家可以网上找找

jenkins显示gitlab的认证报错

描述 使用“List Git branches (and more)”功能&#xff0c;显示gitlab的分支或者标签。报错“org.eclipse.jgit.api.errors.TransportException: http://gitlab.test.com/userCenter/userCenterServer: not authorized” 排查与解决 使用的凭证再gitlab是Maintainer身份&…

c++ nlohmann/json

json为JavaScript object notation 是一种数据格式&#xff0c;逐渐替换掉了传统的xml 。json数据格式的属性名称和字符串值需要用双引号引起来&#xff0c;用单引号或者不用引号会导致读取数据错误。json的另外一个数据格式是数组&#xff0c;和javascript中的数组字面量相同。…

金融计量学第1节课:股指收益率序列统计特征

量化策略开发&#xff0c;高质量社群&#xff0c;交易思路分享等相关内容 导论与介绍 大家好&#xff0c;我是Le Chiffre 今天我们来为大家分享金融计量学系列内容&#xff0c;在松鼠量化3年多分享的内容中&#xff0c;大部分以量化策略为主&#xff0c;至今为止&#xff0c;…

EasyExcel导入导出

在项目开发中往往需要使用到数据的导入和导出&#xff0c;导入就是从Excel中导入到DB中&#xff0c;而导出就是从DB中查询数据然后使用POI写到Excel上。所以今天就为大家带来一款基于阿里EasyExcel的导入导出功能&#xff0c;开放了一个demo&#xff0c;以下是gitee地址&#x…

2.4 逻辑代数的基本定理

学习目标&#xff1a; 如果我要学习逻辑代数的基本定理&#xff0c;我会采取以下步骤&#xff1a; 1. 学习基本概念&#xff1a;首先&#xff0c;我会花时间了解逻辑代数的基本概念&#xff0c;如逻辑运算符&#xff08;合取、析取、否定等&#xff09;、真值表、逻辑等价性等…

Splashtop 与 Pax8 合作为 MSP 提供简化的远程支持解决方案

2023年4月27日 科罗拉多州丹佛 Pax8 是一个行业领先的云商务市场&#xff0c;该公司今天宣布将通过 Pax8 市场在全球推出其全新运营供应商 Splashtop。Splashtop 的远程访问、支持以及端点监控和管理解决方案极具成本效益&#xff0c;而且功能强大&#xff0c;可以助力托管服务…