Facebook升级到MySQL 8.0付出的代价

6337d559bcb0ebea6175bf5b6473934a.png

近日,Facebook 官博公布了他们的数据库版本从 MySQL 5.6 升级到了 MySQL 8.0,并且在官博记录了复盘详细的升级过程。

Facebook 称,他们最近的一次大版本升级到 MySQL 5.6 花了一年多时间才完成,还在 5.6 版上开发 LSM 树存储引擎,MyRocks。在升级到 5.7 的同时构建一个新的存储引擎,会大大减慢 MyRocks 的进度,因此我们选择继续使用 5.6,直到 MyRocks 完成,MySQL 5.6 的寿命也即将结束,决定升级到 MySQL 8.0 。

官博介绍说,此次过程比之前的升级更具挑战。

MySQL 是由 Oracle 公司开发的一个开源数据库,它为 Facebook 的一些最重要的工作负载提供了动力。我们积极开发 MySQL 中的新特性,以支持不断演化的需求。这些特性对MySQL的许多方面进行了修改,包括客户机连接器、存储引擎、优化器以及复制。为了迁移工作负载,对于每个新的 MySQL 主版本,我们都需要投入大量的时间和精力。其中的挑战包括:

  • 将自定义功能移植到新版本

  • 确保主要版本之间的复制兼容

  • 最小化现有应用程序查询所需的更改

  • 对阻碍服务器支持我们工作负载的性能退化进行修复。

我们最近一次的主版本升级是到 MySQL 5.6,它花了一年多的时间才推出。当5.7 版发布时,我们还在 5.6 版上开发 LSM 树存储引擎和 MyRocks。在升级到 5.7 的同时构建一个新的存储引擎,会大大减慢 MyRocks 的进度,因此我们选择继续使用 5.6,直到 MyRocks 完成。MySQL 8.0 发布之际,我们正在做 MyRocks 向用户数据库(UDB)服务层推出的收尾。

该版本包括一些引人注目的特性,如基于写集的并行复制和提供原子 DDL 支持的事务数据字典等。对我们来说,迁移到 8.0 还将带来包括文档存储在内的,我们已经错过的 5.7 特性。版本 5.6 的使命即将结束,我们希望在 MySQL 社区中保持活跃,尤其是在 MyRocks 存储引擎上的工作。

8.0 中的增强功能,比如即时 DDL,可以加快 MyRocks 的模式更改,但是我们需要在 8.0 的代码库中使用它。考虑到更新代码的好处,我们决定迁移到 8.0。下面将分享我们如何解决 8.0 迁移项目的难题,以及在这个过程中发现的一些惊喜。当最初确定项目范围时,可以明确的是,迁移到 8.0 会比迁移到 5.6 或 MyRocks 更困难。

  • 当时,我们定制的 5.6 分支有 1700 多个代码补丁需要移植到 8.0。在我们移植这些更改时,新的 Facebook 的 MySQL 特性和修复已被添加到5.6 的代码库中,从而使目标变得更加遥不可及。

  • 我们有许多 MySQL 服务器在生产环境中运行,为大量截然不同的应用程序提供服务。我们还有众多管理 MySQL 实例的软件架构。这些应用执行诸如收集统计数据或管理服务器备份之类的操作。

  • 从 5.6 升级到 8.0 完全跳过了 5.7。在 5.6 中处于活动状态的 API 在 5.7中可能被弃用,而在 8.0 中可能会被移除,这要求我们必须更新所有使用了现已删除API的应用程序。

  • 许多 Facebook 功能与 8.0 中的类似功能并不向前兼容,需要一种弃用或迁移途径。

  • MyRocks 的增强功能需要在 8.0 中运行,包括本地化分区和崩溃恢复。

1、代码补丁

首先我们建立了 8.0 分支,用于在开发环境中进行构建和测试。然后,我们开始从 5.6 分支移植补丁的漫长过程。开始的时候有 1700 多个补丁,但我们能将其组织成几个主要类别。

我们的大多数自定义代码都有很好的注释和描述,因此可以很容易地确定应用程序是否仍然需要它,或者是否可以将它删除。通过特殊关键字或唯一变量名所启用的功能,也使得确定关联变得很容易,因为我们可以搜索应用程序代码库来找到它们的用例。有些补丁非常晦涩难懂,需要做调查工作 — 挖掘旧的设计文档、邮件或代码评审注释,以了解它们的历史。

我们将每个补丁分入四类之一:

  1. Drop:不再使用,或在8.0中具有同等功能的特性,不需要移植。

  2. Build/Client:支持我们构建环境的非服务器特性,修改过的 MySQL 工具,比如 mysqlbinlog,或者增加的功能,如异步客户端 API 等,需要移植。

  3. 非 MyRocks 服务器:mysqld 服务器中与 MyRocks 存储引擎无关的特性,需要移植。

  4. MyRocks 服务器:支持 MyRocks 存储引擎的特性,需要移植。

我们使用电子表格跟踪每个补丁的状态和相关历史信息,并且在删除补丁时记录理由。更新相同特性的多个补丁被组在一起进行移植。移植并提交到 8.0 分支的补丁,用 5.6 提交信息进行了注释。由于我们需要筛选大量的补丁,将不可避免地出现移植状态上的差异,这些注释帮助我们解决了此类问题。

客户端和服务器类别中的每个补丁都自然而然地成为一个软件发布里程碑。随着所有与客户端相关的更改的移植,我们能够将客户端工具和连接器代码更新到8.0。一旦所有非 MyRocks 服务器特性都被移植,我们就可以为 InnoDB 服务器部署8.0 mysqld了。完成 MyRocks 服务器特性移植使我们能够更新 MyRocks 安装。

有些复杂特性需要对 8.0 进行重大更改,一些方面存在很大的兼容性问题。例如,上游 8.0 binlog 事件格式与我们一些对 5.6 的定制修改不兼容。Facebook 5.6 特性使用的错误代码与上游 8.0 分配给新特性的错误代码冲突。我们最终需要修补 5.6 服务器,以使其与 8.0 向前兼容。

完成所有这些特性的移植花了几年时间。到最终结束时,我们已经评估了 2300 多个补丁,并将其中 1500 个移植到了 8.0 版本。

2、迁移途径

我们将多个 mysqld 实例组合到一个 MySQL 副本集中。副本集中的每个实例都包含相同的数据,但在地理上分布到不同的数据中心,以提供数据可用性和故障切换支持。每个副本集都有一个主实例。其余的实例都是从实例。主实例处理所有写流量,并将数据异步复制到所有从实例。

由 5.6 主/5.6 从所组成的副本集开始,最终目标是包含 8.0 主/ 8.0 从的副本集。我们遵循一个类似于 UDB MyRocks migration plan 的迁移规划。

  1. 对于每个副本集,通过一个使用 mysqldump 生成的逻辑备份,创建并添加到 8.0 的从实例。这些从实例不提供任何应用程序读取流量;

  2. 在 8.0 从实例上开启读取流量;

  3. 允许将 8.0 从实例升级为主实例;

  4. 禁用 5.6 实例的读取流量;

  5. 移除所有 5.6 实例。

每个副本集可以独立地通过上述步骤进行迁移,并可根据需要停留在一个步骤上。我们将副本集分成更小的组,在组中进行每一次迁移。如果发现问题,我们可以回滚到上一步。在某些情况下,副本集能够在其它副本集开始之前到达最后一步。

为了自动化迁移大量副本集,我们需要构建新的软件架构。可以通过简单地更改配置文件中的一行,将副本集组合并在每个阶段中移动它们。任何遇到问题的副本集都能单独回滚。

3、基于行的复制

作为 8.0 迁移工作的一部分,我们决定将使用基于行的复制(row-based replication,RBR)作为标准。一些 8.0 特性需要 RBR,并且它简化了 MyRocks 的移植工作。我们的大多数 MySQL 副本集已经在使用 RBR,而那些仍然运行基于语句的复制(statement-based replication,SBR)的副本集不容易迁移。这些副本集通常有不含任何高基数键的表。完全转向 RBR 是一个目标,但添加主键所需的长尾工作的优先级往往低于其它项目。

因此,我们将 RBR 作为 8.0 的要求。在评估并向每个表添加主键之后,我们今年切换了最后一个 SBR 副本集。使用 RBR 还为我们提供了一个解决应用程序问题的替代解决方案,我们在将一些副本集移动到 8.0 主实例时遇到了这个问题,将在后面讨论。

4、自动化验证

大多数 8.0 迁移过程都涉及使用我们的自动化架构和应用查询来测试和验证 mysqld 服务器。

我们用来管理服务器的自动化基础架构在随着 MySQL 服务器的增长而增长。为了确保所有 MySQL 自动化组件都与 8.0 版本兼容,我们投资构建了一个测试环境,该环境利用虚拟机上的测试副本集来验证行为。我们为 canary 编写了在 5.6 版本和 8.0 版本上运行的每个自动化组件的集成测试,并验证了它们的正确性。在进行此演练时,我们发现了几个错误和行为差异。

当 MySQL 架构的每一部分都在我们的 8.0 服务器上进行验证时,我们发现并修复了(或解决了)一些有趣的问题:

解析错误日志、mysqldump 输出或服务器 show 命令的文本输出的软件很容易损坏。服务器输出的细微变化常常会暴露出工具解析逻辑中的错误。

  1. 8.0 的默认 utf8mb4 排序规则设置导致 5.6 和 8.0 实例之间的排序规则不匹配。8.0 表可能会使用新的 utf8mb4_0900 排序规则,即使对于由 5.6 的show create table生成的create语句也是如此,因为使用utf8mb4_general_ci 的 5.6 模式没有显式指定排序规则。这些表差异通常会导致复制和模式验证工具出现问题;

  2. 某些复制失败的错误代码发生了变化,我们必须修复我们的自动化程序来正确处理它们;

  3. 8.0 版本的数据字典废弃了 table.frm 文件,但是我们的一些自动化系统使用它们来检测表模式的修改;

  4. 我们必须更新自动化系统,以支持 8.0 中引入的动态权限。

5、应用程序验证

我们希望迁移对应用程序尽可能透明,但是有些应用程序的查询会出现性能退化,或者在8.0 上会失败。

对于 MyRocks 迁移,我们构建了一个 MySQL 影子测试框架,该框架捕获生产流量并将其重放到测试实例中。对于每个应用程序工作负载,我们在 8.0 上创建了测试实例,并向它们回放影子流量的查询。我们捕获并记录了从 8.0 服务器返回的错误,并发现了一些有趣的问题。不幸的是,并非所有这些问题都是在测试过程中发现的。例如,事务死锁是应用程序在迁移过程中发现的。在研究不同的解决方案时,我们可以暂时将这些应用程序回滚到 5.6 版本。

  • 8.0 引入了新的保留关键字,其中一些关键字,如 groups 和 rank,与应用程序查询中常用的表列名或别名相冲突。这些查询没有通过反引号转义名称,导致解析错误。使用了自动转义查询中列名的软件库的应用程序没有遇到这些问题,但并非所有应用程序都使用这些软件库。解决这个问题很简单,但是需要时间来跟踪生成这些查询的应用程序属主和代码库。

  • 在 5.6 和 8.0 之间还发现了有些 REGEXP 不兼容。

  • 一些包含在 InnoDB 上的 insert ... on duplicate key 查询的应用程序遇到了 repeatable-read 事务死锁。5.6 有一个 bug,在 8.0 中得到了修复,但是修复增加了事务死锁的可能性。在分析了查询之后,我们能够通过降低隔离级别来解决该问题。这个选项对我们来说是可用的,因为我们已经切换到基于行的复制。

  • 我们自定义的 5.6 文档存储和 JSON 函数与 8.0 不兼容。使用文档存储的应用程序需要将文档类型转换为文本以进行迁移。对于 JSON 函数,我们向 8.0 服务器中添加了兼容 5.6 的版本,以便应用程序以后可以迁移到 8.0 API。

我们对 8.0 服务器的查询和性能测试发现了一些需要立即解决的问题。

  • 我们发现在 ACL 缓存部分出现了新的互斥争用热点。当大量连接同时打开时,它们都会阻塞 ACL 检查;

  • 当存在大量 binlog 文件并且 binlog 的高速写入导致频繁轮换文件时,binlog 索引访问也发现了类似的争用;

  • 几个涉及临时表的查询被中断。这些查询会返回意外错误,或者运行时间太长以致超时。

内存使用量与 5.6 相比有所增加,特别是对于 MyRocks 实例,因为必须加载 8.0 中的 InnoDB 。默认的 performance_schema 设置启用了所有工具集并消耗了大量内存。我们限制了内存使用,只启用了少量的工具,并对代码进行了更改,以禁用无法手动关闭的表。

然而,并不是所有增加的内存都是分配给 performance_schema 的。我们需要检查和修改各种 InnoDB 内部数据结构,以进一步减少内存占用。这一努力使 8.0 的内存使用率降到了可以接受的水平。

6、接下来的工作

到目前为止,8.0 的移植已经花了几年时间。我们已将许多 InnoDB 副本集转换为完全在 8.0 上运行。剩下的大部分都处于迁移途径的不同阶段。现在,我们的大多数定制功能都已移植到 8.0,更新到 Oracle 的次版本相对容易些,我们计划跟上最新版本的步伐。

跳过 5.7 这样的主版本会带来一些问题,我们的迁移需要解决这些问题。

首先,我们无法就地升级服务器,需要使用逻辑转储和还原来构建新服务器。但是,对于非常大的 mysqld 实例,这可能需要在活跃生产服务器上运行很多天,而且这个脆弱的过程可能会在完成之前被中断。对于这些大型实例,我们必须修改备份和恢复系统来应对重建。

其次,检测 API 更改要困难得多,因为 5.7 可能会向我们的应用程序客户端发出不推荐警告,以提示修复潜在的问题。而我们需要在迁移生产工作负载之前,运行额外的影子测试来查找失败。使用自动转义模式对象名称的 mysql 客户端软件,有助于减少兼容性问题的数量。

在一个副本集中支持两个主版本非常困难。一旦副本集将其主实例升级为 8.0,最好尽快禁用并移除 5.6 实例。应用程序用户往往会发现只有 8.0 支持的新特性,比如 utf8mb4_0900 排序规则,使用这些排序规则可能中断 8.0 和 5.6 实例之间的复制流。

尽管我们在迁移过程中遇到了种种障碍,但我们已经看到了运行 8.0 带来的好处。一些应用程序选择了提早迁移到 8.0,以利用诸如文档存储和改进的日期时间支持等功能。我们一直在考虑如何在 MyRocks 上支持像即时DDL这样的存储引擎特性。总的来说,新版本大大扩展了 MySQL@Facebook 的功能。

作者 | Herman Lee,Pradeep Nayak 原文:https://engineering.fb.com/2021/07/22/data-infrastructure/mysql/ 译者 | 王雪迎  责编 | 晋兆雨 出品 | CSDN(ID:CSDNnews)

< END >

往期精选:

再见收费的Navicat,操作数据库靠它就够了!

MyBatis原生批量插入的坑与解决方案!

MyBatis 批量插入数据的 3 种方法!

更多精彩,点击关注公众号

7011e39f01345a2337006ebd6567ae78.png7a6d433a06e7acf2df678e1b6a2feb5e.png7f12700d1f3259488fe258b335121c12.png

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

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

相关文章

Matlab制作朱利表

朱利判据 其中 {bn−kan−k−ana0∗akcn−kbn−k−bnb0∗bk...qn−kpn−k−pnp0∗pk\begin{cases} b_{n-k}a_{n-k}-\frac{a_n}{a_0}*a_k\\ c_{n-k}b_{n-k}-\frac{b_n}{b_0}*b_k\\ ...\\ q_{n-k}p_{n-k}-\frac{p_n}{p_0}*p_k \end{cases}⎩⎪⎪⎪⎨⎪⎪⎪⎧​bn−k​an−k​−a0…

高并发下秒杀商品,必须知道的9个细节

高并发下如何设计秒杀系统&#xff1f;这是一个高频面试题。这个问题看似简单&#xff0c;但是里面的水很深&#xff0c;它考查的是高并发场景下&#xff0c;从前端到后端多方面的知识。秒杀一般出现在商城的促销活动中&#xff0c;指定了一定数量&#xff08;比如&#xff1a;…

最小拍控制系统详细解读(阶跃输入+速度输入2个案例)【Simulink仿真】

目录索引1.符号说明与结构框图2.最小拍控制系统构造原则2.1数字控制器D(z)的构造3.简单控制对象的最小拍控制器设计3.1阶跃输入3.2速度输入1.符号说明与结构框图 y(k)——系统响应输出的离散值u(k)——数字PID控制输出的离散值r(k)——期望输出的离散值&#xff08;事先已知&a…

SpringBoot官方热部署和远程调试神器,真带劲!

平时使用SpringBoot开发应用时&#xff0c;修改代码后需要重新启动才能生效。如果你的应用足够大的话&#xff0c;启动可能需要好几分钟。有没有什么办法可以加速启动过程&#xff0c;让我们开发应用代码更高效呢&#xff1f;今天给大家推荐一款SpringBoot官方的热部署工具spri…

【Python】输入任意个数元素并保存至列表

目录1.导入任意个数元素到列表1.1.编程思路1.2.代码片2.查找一个重复元素在列表中的所有位置2.1.编程思路2.2代码片1.导入任意个数元素到列表 1.1.编程思路 输入未知个数的元素需要用列表来存储&#xff0c;由于Python具有内存的动态分配能力&#xff0c;列表不需要手动动态分…

MySQL 性能优化的 9 种姿势,面试再也不怕了!

大家好&#xff0c;我是磊哥&#xff01;今天给大家分享一些简单好用的数据库优化方式&#xff01;1、选择最合适的字段属性Mysql是一种关系型数据库&#xff0c;可以很好地支持大数据量的存储&#xff0c;但是一般来说&#xff0c;数据库中的表越小&#xff0c;在它上面执行的…

Excel的规划求解【详细步骤】

本文目录1.说明2.准备加载项步骤1步骤2步骤33.线性规划问题步骤4步骤5步骤61.说明 使用Lingo程序也可以实现线性规划、非线性规划以及0-1规划&#xff0c;但是在缺少Lingo程序的情况下&#xff0c;我们使用Excel照样可以很容易地完成。在这里我给大家提供了解决此类问题的详细…

4 种方法!检查字符串是否为合法的日期格式

哈喽大家好&#xff0c;今天咱们来讲一下&#xff0c;Java 中如何检查一个字符串是否是合法的日期格式&#xff1f;为什么要检查时间格式&#xff1f;后端接口在接收数据的时候&#xff0c;都需要进行检查。检查全部通过后&#xff0c;才能够执行业务逻辑。对于时间格式&#x…

【Matlab】根据图生成带权邻接矩阵,并求出最短路径

目录图的简介无向图&#xff08;Graph&#xff09;生成带权邻接矩阵求两点最短路径有向图&#xff08;Digraph&#xff09;生成带权邻接矩阵求最短路径图的简介 图是拓扑学中的一个重要概念&#xff0c;分为无向图和有向图两种。图有两个重要属性&#xff0c;即点&#xff08;…

阿里二面:为什么要分库分表?

在高并发系统当中&#xff0c;分库分表是必不可少的技术手段之一&#xff0c;同时也是BAT等大厂面试时&#xff0c;经常考的热门考题。你知道我们为什么要做分库分表吗&#xff1f;这个问题要从两条线说起&#xff1a;垂直方向 和 水平方向。1 垂直方向垂直方向主要针对的是业务…

Java 中 List 分片的 5 种方法!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;前些天在实现 MyBatis 批量插入时遇到了一个问题&#xff0c;当批量插入的数据量比较大时&#xff0c;会导致程序执行报错&a…

Matlab仿真炮弹飞行轨迹——探究射弹参数对飞行轨迹的影响

目录1.分析炮弹受力2.设定参数并仿真3.通过仿真寻找最佳射弹速度3.1.射弹角度的影响3.2.射弹速率的影响3.3.炮弹属性和空气的影响3.3.1.空气阻力系数的影响3.3.2.炮弹质量的影响1.分析炮弹受力 假设炮弹在飞行过程中可以看成质点&#xff0c;运动时仅考虑初始速度、重力加速度…

50行代码,搞定敏感数据读写!

每天早上七点三十&#xff0c;准时推送干货一、介绍在实际的软件系统开发过程中&#xff0c;由于业务的需求&#xff0c;在代码层面实现数据的脱敏还是远远不够的&#xff0c;往往还需要在数据库层面针对某些关键性的敏感信息&#xff0c;例如&#xff1a;身份证号、银行卡号、…

【Python】导入资源管理器的文件列表(计算文件和文件夹大小)

文章目录1.按照扩展名进行分类2.导出文件的大小3.计算文件夹大小4.分类到字典5.完整代码及效果1.按照扩展名进行分类 使用Python查询一个路径下的所有文件可以借助glob模块以及os模块。 在导入文件列表之前&#xff0c;我们需要指定我们的操作目录&#xff0c;操作目录一经指定…

HashMap 中的一个“坑”!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;最近公司新来了一个小伙伴&#xff0c;问了磊哥一个比较“奇怪”的问题&#xff0c;这个问题本身的难度并不大&#xff0c;但…

【Python】交互式界面创建函数

文章目录简介规则思路示例代码与运行效果简介 运行Python时&#xff0c;在程序运行过程中手动输入一个函数表达式&#xff0c;并将其作为一个函数进行后续的调用工作&#xff0c;类似于Matlab里面的匿名函数。这个功能使用传统语言会相当麻烦&#xff0c;当然&#xff0c;我也…

原生 js前端路由系统实现3之代码 构建工具 和 querystring功能

为什么80%的码农都做不了架构师&#xff1f;>>> 构建 目前前端构建工具流行的是 grunk.js 功能是大而全&#xff0c;但往往大而全的东西为了多样性 需要做额外的配置 我还是想要有一个专门为自己特性项目而生构建工具 我不想加载第三方的node模块&#xff0c;也不…

单例模式,真不简单

前言单例模式无论在我们面试&#xff0c;还是日常工作中&#xff0c;都会面对的问题。但很多单例模式的细节&#xff0c;值得我们深入探索一下。这篇文章透过单例模式&#xff0c;串联了多方面基础知识&#xff0c;非常值得一读。1 什么是单例模式&#xff1f;单例模式是一种非…

【python】最优化方法之一维搜索(黄金分割法+斐波那契法)

文章目录1.概念2.遍历搜索3.优化算法3.1.一维搜索原则3.2.黄金分割法Code Block3.3.斐波拉契法Code Block1.概念 \qquad一维搜索是最优化方法最简单的一种&#xff0c;即求一个在(a,b)内&#xff0c;连续下单峰函数f(x)f(x)f(x)的极小值。所谓下单峰函数就是只有一个极小值的函…

MySQL系列之E-1------MySQL主从复制原理

主从复制是异步复制,可以通过google的一个插件实现半同步E.1 主从复制原理1、建立主从复制的用户名和密码2、将master上主库需要进行复制的库“锁库”3、通过mysqldump备份master上主库&#xff0c;“解锁“&#xff0c;在slave端进行恢复4、更改配置文件5、在丛库上执行change…