PlanetScale 如何进行模式变更
在 PlanetScale,我们将工程团队的效率提升视为首要任务,不仅是为了自身团队,也是为了使用我们工具的所有开发者。
在开发 PlanetScale 的早期,我们的目标之一是为工程团队提供最优秀的模式变更流程。在过去的三年中,我们反复迭代这个流程,现在逐渐满意地看到,应用程序模式的变更变得如此简单。
我们的主 API 是一个基于 Ruby on Rails 的应用程序,连接到两个 PlanetScale 数据库。其中一个数据库存储大部分业务和用户数据,另一个则是一个面向更大规模的分片数据库,用于支持 PlanetScale Insights 的庞大交互需求。
我们的团队几乎每天对这些数据库进行模式变更。我们通过与为客户构建的工具完全相同的方式进行变更,并且引入了我们自己的“GitHub Actions Bot”,以自动化与 Rails 应用程序相关的一些步骤。在这篇文章中,我会分享我们当前在 PlanetScale 上进行模式变更的流程。
生产数据库模式变更
全球绝大多数的 Rails 应用程序都会在每次部署中更新生产环境的模式。他们通常在 CI(持续集成)的流程中,在部署代码到生产环境之前立即运行 rails db:migrate
。这种流程对许多团队来说运行良好,但当数据量和工程团队规模增长时,这种方法可能会导致一些问题。
我们观察到的两个主要问题是:
- 随着数据量增长,直接对生产环境运行模式变更(DDL)变得越来越危险且耗时;
- 较大的团队频繁部署时,容易被彼此的模式变更阻碍,导致更高的协调成本。
痛苦的迁移流程代价高昂。当这些问题对团队影响严重时,工程师可能倾向于避免模式变更,通过不同的设计方式开发功能,或者错误地滥用 JSON 列来替代适当的模式设计。
问题的解决方案: 这始于打破模式迁移和代码之间的绑定,允许两者独立进行。这么做有很多好处,最大的一点在于工程师必须更深入地思考代码与数据库模式变更之间的交互。
接下来就是引入一种在线模式变更工具。
在线模式变更
“在线”(Online)是数据库圈中用来描述无需停机即可完成的变更的术语。Rails 社区在构建工具和教育用户如何完成无停机迁移方面做得非常好。每个 Rails 开发者都熟悉哪些模式变更可能导致锁定。社区甚至开发了指导我们安全进行变更的 gems(扩展组件)。
尽管有所有这些教育和工具,如果没有数据库层面的解决方案,问题仍无法完全解决。
许多应用程序开发者不知道,大规模公司实际上已经构建了一套工具来解决这个问题,这些工具被称为在线模式变更(Online Schema Change)工具。这些工具取代了 rails db:migrate
,使得生产数据库在运行模式变更时不受影响。其优势在于,应用开发者不再需要担心哪些模式变更可能导致表锁定。通过这种工具,模式变更可以始终以安全的方式完成,从而减少了人们对模式变更的恐惧。
你能想到的大多数大规模公司都在使用某种在线模式变更工具来处理他们的数据库迁移。
在 PlanetScale,这种在线模式变更工具由我们团队负责维护,并且直接内置于 PlanetScale 的 **安全迁移**功能中。
应用代码与模式变更的配合
每次对数据库进行模式变更时,还需要密切考虑应用层如何处理这些变更。即便拥有最先进的模式变更工具,如果在应用与数据库交互的方式上出错,依然可能导致停机。
许多开发者一个常见的误解是认为可以原子性地同时部署模式与应用代码。这实际上是不可能的。对于每一个模式变更,应用层都需要能够处理当前模式和未来模式,否则就会出现错误。
一个完善的工作流程需要在数据库和应用层面同时具备解决方案。
我们的模式变更工作流程
在 PlanetScale,当开发者开始进行模式变更时,流程从本地开发开始。应用代码在一个 git 分支中进行修改,与数据库模式相关的任何更改会应用到本地 MySQL 实例中。完成本地开发和测试后,开发者提交代码并在 GitHub 上创建一个 Pull Request(PR)。
Pull Request 机器人
我们构建了一个基于 GitHub Actions 的 “Pull Request Bot”,能够检测 PR 中需要进行的模式变更。当发现变更时,它会自动创建一个 PlanetScale 分支、运行迁移、发起一个部署请求(PlanetScale 中进行模式变更的方式),并在 GitHub 中评论迁移结果。
GitHub 机器人在 Pull Request 中的评论截图
关于此工作流程的一些说明:
- 只有在存在模式变更时才创建 PlanetScale 分支;
- 我们的 CI 流程使用本地 MySQL 执行测试,以实现最低延迟;
- 我们使用
planetscale_rails
gem 来运行迁移。
每个应用的具体步骤可能不同,但整体流程类似。
通过机器人,我们能够利用 PlanetScale API 检测数据库变更的类别。机器人根据变更特性生成评论,包括指导如何安全地进行这些变更的步骤。不同的应用程序有各自的需求,但它们在进行模式变更时有着类似的需求,比如:
- 移除列时,需要先部署应用代码,然后修改数据库模式;
- 新增列时,需要先修改数据库模式,然后部署应用代码。
参考: 关于这一范式的详细分析,请查看我们的向后兼容数据库变更博客。
部署请求
机器人会自动为我们发起部署请求,并在 GitHub 留下链接评论。这样,团队可以同时审核模式变更和代码变更,了解变更的原因和内容。
PlanetScale 部署请求截图
在模式变更部署之前,lint 工具会对代码进行检查,以捕获任何常见错误。
部署请求会通过 Vitess 的在线迁移工具执行模式变更。这不仅保护了生产环境,还允许我们在出现问题时快速回滚模式变更。
如果有多个团队成员同时进行模式变更,PlanetScale 会为每个变更创建一个队列。这使得变更可以按队列中的顺序自动部署,同时增强了安全性。PlanetScale 不仅会对每个模式变更进行安全检查,还会在结合所有变更后的结果模式上运行完整检查。这有效地防止多人同时更改时出现的错误。
我该如何实现这一流程?
通过结合 GitHub Actions Bot 与 PlanetScale 部署请求,我们的模式变更流程非常顺畅。开发者可以快速完成变更,同时确保变更不会对生产环境造成影响。
机器人将 PlanetScale 的在线模式变更工具与我们的 Rails 应用的具体需求结合起来,使开发者能够在速度和信心之间取得平衡。
我们故意将代码和模式的部署流程分离开,迫使工程师认真规划每一步变更,同时使我们能够快速行动,而不被其他团队成员的模式迁移阻碍。
虽然我们使用 GitHub Actions 实现了此机器人,但其他 CI 工具也可以构建类似的工作流程。在 PlanetScale 的方面,所有所需 API 调用均可以通过 pscale CLI
实现。
我们在GitHub Actions 文档页面中发布了许多关键的工作流程示例。你可以根据团队和应用的需求,混合和匹配这些示例。
如果你有一个 Rails 应用,我们也在 planetscale_rails
的 README 文件中发布了直接适配的指南说明。
关注公众号:程序新视界,一个让你软实力、硬技术同步提升的平台
除非注明,否则均为程序新视界原创文章,转载必须以链接形式标明本文链接