前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >GitHub分享了他们将自己1200+节点、300+TB数据存储的MySQL从5.7升级至8.0的故事

GitHub分享了他们将自己1200+节点、300+TB数据存储的MySQL从5.7升级至8.0的故事

原创
作者头像
贺春旸的技术博客
发布2023-12-09 21:35:34
2580
发布2023-12-09 21:35:34
举报
文章被收录于专栏:DBA 平台和工具DBA 平台和工具

GitHub分享了他们将自己1200+节点、300+TB数据存储的MySQL集群从5.7升级至8.0的故事

官方文献: https://github.blog/2023-12-07-upgrading-github-com-to-mysql-8-0/

全文译:

15 年前,GitHub 从一个带有单一 MySQL 数据库的 Ruby on Rails 应用程序起步。从那时起,GitHub 不断发展 MySQL 架构,以满足平台的扩展和弹性需求,包括构建高可用性、实施自动化测试和数据分区。如今,MySQL 仍是 GitHub 基础架构的核心部分,也是我们首选的关系型数据库。

这就是我们如何将 1200 多台 MySQL 主机升级到 8.0 的故事。在不影响我们的服务水平目标(SLO)的情况下升级主机群并非易事--规划、测试和升级本身就花费了一年多的时间,并且需要 GitHub 内部多个团队的通力协作。

升级动机

为什么要升级到 MySQL 8.0?随着 MySQL 5.7 的生命周期即将结束,我们将我们的系统升级到了下一个主要版本,即 MySQL 8.0。我们还想使用能获得最新安全补丁、错误修复和性能增强的 MySQL 版本。此外,我们还希望测试 8.0 中的新功能并从中受益,包括即时 DDL、隐形索引和压缩的 bin 日志等。

GitHub 的 MySQL 基础架构

在深入探讨如何进行升级之前,让我们先从 10,000 英尺的高度来看看我们的 MySQL 基础架构:

  1. 我们的机群由 1200 多台主机组成。这是 Azure 虚拟机和数据中心裸机主机的组合。
  2. 我们在 50 多个数据库集群中存储 300 多 TB 的数据,每秒提供 550 万次查询。
  3. 每个集群都采用主集群加副本集群的高可用性配置。
  4. 我们的数据是分区的。我们利用水平和垂直分片来扩展 MySQL 集群。我们有存储特定产品领域数据的 MySQL 集群。我们还有水平分片的 Vitess 集群,用于存储超出单主 MySQL 集群的大型领域数据。
  5. 我们拥有一个庞大的工具生态系统,包括 Percona Toolkit、gh-ost、orchestrator、freno 以及用于运营机群的内部自动化工具。

所有这一切构成了一个多样而复杂的部署,需要在保持 SLO 的同时进行升级。

准备旅程

作为 GitHub 的主要数据存储,我们对可用性要求很高。由于我们团队的规模和 MySQL 基础设施的重要性,我们对升级过程有一些要求:

  1. 我们必须能够在遵守服务级别目标(SLO)和服务级别协议(SLA)的前提下升级每个 MySQL 数据库。
  2. 我们无法在测试和验证阶段考虑到所有故障模式。因此,为了保持在 SLO 范围内,我们需要能够在不中断服务的情况下回滚到以前的 MySQL 5.7 版本。
  3. 我们的 MySQL 机群拥有非常多样化的工作负载。为了降低风险,我们需要对每个数据库集群进行原子升级,并围绕其他重大变更安排升级时间。这意味着升级过程将是一个漫长的过程。因此,我们从一开始就知道,我们需要能够持续运行混合版本环境。

升级的准备工作于 2022 年 7 月开始,在升级单个生产数据库之前,我们就已经达到了几个里程碑。

为升级准备基础设施

我们需要为 MySQL 8.0 确定适当的默认值,并执行一些基线性能基准测试。由于我们需要运行两个版本的 MySQL,因此我们的工具和自动化需要能够处理混合版本,并了解 5.7 和 8.0 之间的新语法、不同语法或废弃语法。

确保应用程序的兼容性

我们为所有使用 MySQL 的应用程序将 MySQL 8.0 添加到持续集成 (CI)。我们在 CI 中并行运行了 MySQL 5.7 和 8.0,以确保在漫长的升级过程中不会出现倒退。我们在 CI 中检测到了各种错误和不兼容性,帮助我们删除了任何不支持的配置或功能,并转义了任何新的保留关键字。

为了帮助应用程序开发人员过渡到 MySQL 8.0,我们还启用了一个选项,以便在 GitHub Codespaces 中选择一个 MySQL 8.0 预构建容器进行调试,并提供了 MySQL 8.0 开发集群以进行额外的预开发测试。

沟通和透明度

我们使用 GitHub 项目创建了一个滚动日历,以便在内部沟通和跟踪升级计划。我们创建了问题模板,跟踪应用程序团队和数据库团队协调升级的清单。

升级计划

为了达到可用性标准,我们采取了渐进式升级策略,在整个过程中允许检查点和回滚。

步骤 1:副本滚动升级

我们首先升级单个副本,并在其仍处于离线状态时进行监控,以确保基本功能稳定。然后,我们启用了生产流量,并继续监控查询延迟、系统指标和应用程序指标。我们逐步将 8.0 复制上线,直到升级了整个数据中心,然后再迭代其他数据中心。我们保留了足够的 5.7 在线副本,以便进行回滚,但我们禁用了生产流量,开始通过 8.0 服务器提供所有读取流量。

步骤 2:更新复制拓扑

通过 8.0 复制提供所有只读流量后,我们对复制拓扑进行了如下调整:

配置一个 8.0 主候选副本,直接复制到当前的 5.7 主副本下。

在该 8.0 复制的下游创建两个复制链:

  1. 一组仅有 5.7 复制(不提供流量,但可随时回滚)。
  2. 一组只有 8.0 个副本(提供流量)。

在进入下一步之前,拓扑在这种状态下只维持了很短的时间(最多几个小时)。

步骤 3:将 MySQL 8.0 主机升级为主数据库主机

我们选择不在主数据库主机上进行直接升级。相反,我们将通过使用 Orchestrator 执行优雅故障切换,将 MySQL 8.0 副本升级为主数据库。此时,复制拓扑包括一个 8.0 主数据库和连接到它的两个复制链:一个用于回滚的 5.7 复制离线集和一个 8.0 复制服务集。

Orchestrator 还被配置为将 5.7 主机列入潜在故障切换候选黑名单,以防止意外故障切换时出现意外回滚。

步骤 4:面向内部的实例类型升级

我们还有用于备份或非生产工作负载的辅助服务器。为了保持一致性,我们随后对这些服务器进行了升级。

第 5 步:清理

确认群集无需回滚并成功升级到 8.0 后,我们移除了 5.7 服务器。验证包括至少一个完整的 24 小时流量周期,以确保在流量高峰期不会出现问题。

回滚能力

保证升级策略安全的一个核心部分是保持回滚到先前版本 MySQL 5.7 的能力。对于读取副本,我们确保有足够的 5.7 版本副本保持在线,以满足生产流量负载的需要,如果 8.0 版本副本性能不佳,则通过禁用它们来启动回滚。对于主系统,为了在不丢失数据或中断服务的情况下进行回滚,我们需要在 8.0 和 5.7 之间保持向后数据复制。

MySQL 支持从一个版本复制到下一个更高的版本,但不明确支持反向复制(MySQL 复制兼容性)。当我们测试在暂存集群上将 8.0 主机升级为主主机时,发现所有 5.7 复制都出现了复制中断。我们需要克服几个问题:

  1. 在 MySQL 8.0 中,utf8mb4 是默认字符集,默认使用更现代的 utf8mb4_0900_ai_ci 整理方式。之前版本的 MySQL 5.7 支持 utf8mb4_unicode_520_ci 整理,但不支持最新版本的 Unicode utf8mb4_0900_ai_ci。
  2. MySQL 8.0 引入了用于管理权限的角色,但在 MySQL 5.7 中不存在这一功能。当一个 8.0 实例晋升为簇中的主实例时,我们遇到了问题。我们的配置管理正在扩展某些权限集,以包含角色语句并执行它们,这破坏了 5.7 复制中的下游复制。我们在升级窗口期间临时调整了受影响用户的已定义权限,从而解决了这个问题。

为了解决字符校对不兼容问题,我们必须将默认字符编码设置为 utf8,并将校对设置为 utf8_unicode_ci。

对于 GitHub.com 整体来说,我们的 Rails 配置确保了字符校对的一致性,并使数据库的客户端配置更容易标准化。因此,我们非常有信心能够为最关键的应用程序保持向后复制。

挑战

在整个测试、准备和升级过程中,我们遇到了一些技术挑战。

Vitess 如何?

我们使用 Vitess 对关系数据进行横向分片。在大多数情况下,升级 Vitess 集群与升级 MySQL 集群并无太大区别。我们已经在 CI 中运行 Vitess,因此能够验证查询的兼容性。在分片集群的升级策略中,我们一次升级一个分片。Vitess 代理层 VTgate 会公布 MySQL 的版本,某些客户端行为依赖于该版本信息。例如,一个应用程序使用的 Java 客户端禁用了 5.7 服务器的查询缓存--因为查询缓存在 8.0 中被移除,所以会产生阻塞错误。因此,一旦给定键空间的单台 MySQL 主机升级,我们就必须确保同时更新 VTgate 设置以宣传 8.0。

复制延迟

我们使用读取复制来扩展我们的读取可用性。 GitHub.com 要求低复制延迟,以便提供最新数据。

在测试的早期阶段,我们遇到了 MySQL 中的一个复制错误,该错误已在 8.0.28 中得到修补:

我们碰巧满足了击中这个错误的所有标准。

  1. 我们使用 replica_preserve_commit_order,因为我们使用基于 GTID 的复制。
  2. 我们的许多集群,当然还有所有最关键的集群,都长期处于高强度负载状态。我们的大多数集群写入量都很大。

由于该漏洞已在上游得到修补,我们只需确保部署的 MySQL 版本高于 8.0.28。

我们还观察到,导致复制延迟的大容量写入在 MySQL 8.0 中更加严重。因此,避免大量写入变得更加重要。在 GitHub,我们使用 freno 根据复制延迟来控制写入工作量。

查询会通过 CI,但在生产环境中会失败

我们知道在生产环境中难免会首次出现问题,因此我们采取了升级副本的渐进式推广策略。我们遇到过通过 CI 的查询,但在生产环境中遇到实际工作负载时却会失败。最值得注意的是,我们遇到了一个问题,即带有大型 WHERE IN 子句的查询会导致 MySQL 崩溃。我们的大型 WHERE IN 查询包含数以万计的值。在这种情况下,我们需要在继续升级之前重写查询。查询采样有助于跟踪和检测这些问题。在 GitHub,我们使用 SaaS 数据库性能监控器 Solarwinds DPM (VividCortex) 进行查询观察。

经验教训

在测试、性能调整和解决发现的问题之间,整个升级过程耗时一年多,GitHub 多个团队的工程师都参与其中。我们将整个系统升级到了 MySQL 8.0,包括暂存集群、支持 GitHub.com 的生产集群以及支持内部工具的实例。这次升级凸显了我们的可观察性平台、测试计划和回滚能力的重要性。测试和逐步推出策略使我们能够及早发现问题,并降低在主要升级中遇到新故障模式的可能性。

虽然采用的是渐进式推广策略,但我们仍然需要在每一步都能够回滚,而且我们需要可观察性来识别信号,以指示何时需要回滚。实现回滚的最大挑战在于保持从新的 8.0 主副本到 5.7 副副本的后向复制。我们了解到,Trilogy 客户端库的一致性为我们提供了更多连接行为的可预测性,并让我们确信来自主 Rails 单体的连接不会破坏向后复制。

但是,对于我们的一些 MySQL 集群,如果连接来自不同框架/语言的多个不同客户端,我们会发现向后复制在几个小时内就会中断,这就缩短了回滚的机会窗口。幸运的是,这种情况很少,我们没有在需要回滚之前发生复制中断的情况。但对我们来说,这是一次教训,让我们认识到,拥有已知且易于理解的客户端连接配置是有好处的。它强调了制定指南和框架以确保此类配置一致性的价值。

之前的数据分区工作取得了成效--它使我们能够针对不同的数据域进行更有针对性的升级。这一点非常重要,因为一个失败的查询会阻碍整个集群的升级,而对不同的工作负载进行分区,可以让我们进行零散升级,减少升级过程中遇到的未知风险的爆炸半径。代价是,这也意味着我们的 MySQL 集群扩大了。

上次 GitHub 升级 MySQL 版本时,我们有五个数据库集群,而现在我们有 50 多个集群。为了成功升级,我们必须投资于可观察性、工具和管理群组的流程。

结论

MySQL 升级只是我们必须进行的例行维护的一种--为我们机队上运行的任何软件提供升级路径对我们来说至关重要。作为升级项目的一部分,我们开发了新的流程和操作能力,以成功完成 MySQL 版本升级。然而,我们在升级过程中仍然有太多需要人工干预的步骤,我们希望减少完成未来 MySQL 升级所需的工作量和时间。

我们预计,随着 GitHub.com 的发展,我们的团队将继续壮大,我们的目标是进一步划分数据,从而随着时间的推移增加 MySQL 集群的数量。建立自动化操作任务和自愈能力可以帮助我们在未来扩展MySQL业务。我们相信,投资于可靠的机群管理和自动化将使我们能够扩展 github 并跟上所需的维护工作,从而提供一个更可预测、更有弹性的系统。

从这个项目中汲取的经验教训为我们的 MySQL 自动化奠定了基础,并将为未来更高效地完成升级铺平道路,但仍需保持同样的谨慎和安全。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 全文译:
  • 升级动机
  • GitHub 的 MySQL 基础架构
  • 准备旅程
  • 为升级准备基础设施
  • 确保应用程序的兼容性
  • 沟通和透明度
  • 升级计划
  • 步骤 1:副本滚动升级
  • 步骤 2:更新复制拓扑
  • 步骤 3:将 MySQL 8.0 主机升级为主数据库主机
  • 步骤 4:面向内部的实例类型升级
  • 第 5 步:清理
  • 回滚能力
  • 挑战
  • Vitess 如何?
  • 复制延迟
  • 查询会通过 CI,但在生产环境中会失败
  • 经验教训
  • 结论
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档