Facebook 使用了大量的MySQL以支持他们最重要的工作。并且他们积极开发了许多MySQL 中的新功能,以支持不断发展的需求。这些更改特性发生在 MySQL 的不同领域,包括客户端连接器、存储引擎、优化器和复制。当Facebook对MySQL 的每个新主要版本进行升级时,会面临许多挑战,包括:
Facebook上一次升级到 MySQL 5.6 的主要版本花了一年多的时间才推出。当 5.7 版发布时,他们仍在开发5.6 版上的LSM-Tree 存储引擎MyRocks。由于担心升级到 5.7 会减缓 MyRocks 的开发进度,他们当时选择了保持 5.6版本,直到 MyRocks的开发完成。MySQL 8.0 是在Facebook将 MyRocks 部署到用户数据库 (UDB) 服务层时发布的。
MySQL8.0版本包括很多引人注目的功能,例如基于写集的并行复制和提供原子 DDL 支持的事务数据字典等等。Facebook希望在 MySQL 社区中保持活跃,尤其是他们在 MyRocks 存储引擎上的工作。8.0 中的增强功能,如即时 DDL,可以加速 MyRocks 架构更改。考虑到代码更新的好处,Facebook决定迁移到 8.0。当他们最初确定项目的范围时,发现迁移到 8.0 比迁移到 5.6 或 MyRocks 更加困难。
Facebook首先设置了 8.0 分支,用于在他们的开发环境中进行构建和测试。然后,他们开始了从 5.6 分支移植补丁的漫长旅程。开始时有 1,700 多个补丁,能够将它们分为几个主要类别。Facebook的大多数自定义代码都有很好的注释和描述,因此他们可以轻松确定应用程序是否仍然需要它,或者是否可以删除。但一些补丁非常模糊,需要挖掘旧的设计文档、帖子或代码审查评论以了解它们的历史。
Facebook用4个类别区分每个补丁的类型:
Facebook使用电子表格跟踪每个补丁的状态和相关历史信息,并在删除补丁时记录他们的推理。更新相同功能的多个补丁被组合在一起进行移植。移植并提交到 8.0 分支的补丁使用 5.6 提交信息进行了注释。不可避免地会出现移植状态的差异,因为他们需要筛选大量补丁,这些注释帮助他们解决了这些问题。
每个客户端和服务器类别成为软件发布的里程碑。移植所有与客户端相关的更改后,Facebook将客户端工具和连接器代码更新到 8.0。一旦移植了所有非 MyRocks 服务器功能,Facebook就能够为 InnoDB 服务器部署 8.0 mysqld。完成 MyRocks 服务器功能使Facebook能够更新 MyRocks 安装。
一些最复杂的功能需要对 8.0 进行重大更改,并且一些领域存在重大兼容性问题。例如, 8.0 binlog 事件格式与我们的一些自定义 5.6 修改不兼容。Facebook 5.6 功能使用的错误代码与上游 8.0 分配给新功能的错误代码相冲突。最终Facebook需要修改 5.6 服务器以与 8.0 向前兼容。
完成所有这些功能的移植花了几年时间。最终,Facebook已经评估了 2,300 多个补丁并将其中的 1,500 个移植到 8.0。
Facebook将多个 mysqld 实例组合成一个 MySQL 副本集。副本集中的每个实例都包含相同的数据,但在地理上分布到不同的数据中心,以提供数据可用性和故障转移支持。每个副本集有一个主实例。其余实例都是辅助实例。主节点处理所有写入流量并将数据异步复制到所有辅助节点。Facebook从由 5.6 主/5.6 从组成的副本集开始,最终目标是具有 8.0 主/8.0 从的副本集。遵循了一个类似于UDB MyRocks 迁移的计划。
每个副本集都可以独立地过渡上述每个步骤,并根据需要停留在一个步骤上。Facebook将副本集分成更小的组,并在每次转换中进行引导。如果发现问题,可以回滚到上一步。在某些情况下,副本集能够在其他步骤开始之前到达最后一步。
为了自动化大量副本集的转换,Facebook构建了新的软件基础设施。它们可以将副本集分组在一起,并通过简单地更改配置文件中的一行来将它们移动到每个阶段。任何遇到问题的副本集都可以单独回滚。
作为 8.0 迁移工作的一部分,Facebook决定使用基于行的复制 (RBR)。一些 8.0 功能需要 RBR,它简化了 MyRocks 移植工作。虽然Facebook的大部分 MySQL 副本集已经在使用 RBR,但仍在运行基于语句的复制 (SBR) 的副本无法轻松转换。这些副本集通常是没有任何高基数键的表。因此,Facebook将 RBR 作为 8.0 的要求。在评估并为每个表添加主键后,他们切换了今年最后一个 SBR 副本集。使用 RBR 还为Facebook提供了一种替代解决方案,用于解决我们在将一些副本集移动到 8.0 主版本时遇到的应用程序问题,稍后将对此进行讨论。
大多数 8.0 迁移过程涉及使用Facebook的自动化基础设施、应用程序查询测试和验证 mysqld 服务器。
随着MySQL 机群的增长,Facebook用来管理服务器的自动化基础设施也在增长。为了确保所有的 MySQL 自动化都与 8.0 版本兼容,Facebook投资构建了一个测试环境,该环境利用测试副本集和虚拟机来验证行为。Facebook编写了集成测试来检测在5.6版本和8.0版本上运行的每一部分自动化,并验证它们的正确性。在进行测试时,Facebook发现了几个错误和行为差异。
由于每个 MySQL 基础设施都针对Facebook的 8.0 服务器进行了验证,他们发现并修复了许多有趣的问题:
Facebook希望应用程序的转换尽可能透明,但一些应用程序查询会出现性能下降或在 8.0 上执行失败。
对于 MyRocks 迁移,Facebook构建了一个 MySQL 影子测试框架,用于捕获生产流量并将其重放到测试实例。对于每个应用程序工作负载,Facebook在 8.0 上构建测试实例并向它们重放影子流量查询。通过捕获并记录了从 8.0 服务器返回的错误,发现了一些有趣的问题。但并非所有问题都在测试过程中被发现。例如,在迁移过程中应用程序发现了事务死锁。在研究不同的解决方案时,Facebook能够暂时将这些应用程序回滚到 5.6。
Facebook对 8.0 服务器的查询和性能测试时,发现了一些需要立即解决的问题。
内存使用与 5.6 相比有所增加,尤其是对于 MyRocks 实例,因为必须加载 8.0 中的 InnoDB。默认的 performance_schema 设置启用了所有指标并消耗了大量内存。Facebook通过仅启用少量指标,并更改代码以禁用无法手动关闭的表来限制内存使用。但是,并非所有增加的内存都由 performance_schema 分配。需要检查和修改各种 InnoDB 内部数据结构,以进一步减少内存占用。这些将 8.0 的内存使用率降低到可接受的水平。
到目前为止,8.0 迁移已经花费了几年时间。Facebook已将许多 InnoDB 副本集转换为完全在 8.0 上运行。其余的大多数都处于迁移路径的不同阶段。现在Facebook的大部分自定义功能都已移植到 8.0,更新到 Oracle 的次要版本相对容易,但我们计划跟上最新版本的步伐。
跳过像 5.7 这样的主要版本引入了Facebook的迁移需要解决的问题。
首先,无法就地升级服务器,需要使用逻辑转储和还原来构建新服务器。但是,对于非常大的 mysqld 实例,这在实时生产服务器上可能需要很多天,而且这个脆弱的过程可能会在它完成之前被中断。对于这些大型实例,Facebook不得不修改备份和恢复系统来处理重建。
其次,检测 API 更改要困难得多,因为 5.7 可以向应用程序客户端提供弃用警告以修复潜在问题。Facebook需要运行额外的影子测试来发现故障,然后才能迁移生产工作负载。使用自动转义架构对象名称的 mysql 客户端软件有助于减少兼容性问题的数量。
在一个副本集中支持两个主要版本是很困难的。一旦副本集将其主实例提升为 8.0 实例,最好尽快禁用并删除 5.6 实例。应用程序用户往往会发现仅 8.0 支持的新功能,例如utf8mb4_0900排序规则,使用这些功能可能会中断 8.0 和 5.6 实例之间的复制流。
尽管在迁移过程中Facebook遇到了所有障碍,但他们已经看到了运行 8.0 的好处。一些应用程序选择提前转换到 8.0,以利用文档存储和改进的日期时间支持等功能。总的来说,新版本极大地扩展了Facebook可以用 MySQL 做的事情。
本文分享自 MySQL解决方案工程师 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!