使用 Skeema 进行模式管理

已发表: 2019-04-26

注意:这篇文章来自 SendGrid 的工程团队。 如需更多类似的技术工程帖子,请查看我们的技术博客。

数据库模式管理的范围从狂野的西部任何人都可以在生产过程中“现场实施”到瀑布式的多步骤、多团队审查过程,其中只有一个受膏的个人可以接触生产数据库。

随着关系数据库中包含的数据对公司变得更有价值,并且数据库的可用性对业务变得更加重要,潜在的破坏性模式更改的障碍就会出现。

早期,数据库管理员 (DBA) 成为数据库的看门人,以保护数据库免受不良事件的影响。 但是,在开发人员和他们的应用程序数据库之间有一个老式的 DBA 会导致应用程序的开发生命周期显着放缓,造成开发和运营的孤岛,并在团队之间产生摩擦。

在当今面向微服务开发运营的世界中,开发人员需要能够自行管理数据库架构更改,因为这是他们的数据,他们最终对应用程序的性能和正常运行时间负责。 DBA 和运营团队需要提供适当的工具和建议,以帮助开发团队成为其数据库的所有者。

我们如何管理架构

我们当前的模式管理流程使用单个 Git 存储库来存储我们所有数据库集群的初始模式,并包含在应用单个表更改/创建和删除时对该模式的所有后续更改:

  • 开发人员在本地进行模式更改并生成更改/创建/删除语句并将其作为拉取请求添加到集成分支。
  • 为数据运营团队创建了一组 Jira 票证,以审查架构更改并将其应用于我们的测试/登台和生产环境。
  • 数据运营团队的成员审查请求的更改并将更改应用到测试/登台环境并将 PR 合并到集成分支。
  • 请求开发人员在我们的测试/暂存环境中测试更改并批准将更改推送到生产环境。
  • 最后,Data Operations 将集成分支合并到 master 并将架构更改应用到生产环境。

鉴于存储在我们数据库中的数据的价值以及让这些数据库始终正常运行的愿望,我们决定采用这种拜占庭式的事件序列来保护自己免受自己的伤害。

保护数据库是一回事,但这个过程引入了几个障碍,以可靠和有效的方式进行模式更改:

  • 每周两次审查和进行架构更改,并且很容易脱轨,因为多个团队在同一个 Git 存储库中处理不同的数据库,并且每个人都依赖数据运营团队中的某个人来审查和更改各种环境。
  • 为所有关系数据库模式拥有一个存储库可能会导致发布过程具有挑战性。 如果有其他模式更改尚未准备好推送到生产环境但处于暂存状态等待额外测试,则对已准备好用于生产的一个模式的更改无法进入生产环境。
  • 数据运营团队是一个小团队,它成为了一个瓶颈,试图管理哪些变更可以和不能在何时投入生产。 调度冲突和人员可用性确实会减慢新功能的发布或对当前应用程序的修复。
  • 我们正在使用拉取请求和 Jira 票证中的注释手动将这些更改应用于生产系统; 有时复制粘贴可能会出错。

输入 Skeema(和一些助手)

为了消除这些流程障碍,使架构更改不易出现人为错误,允许开发人员管理自己的应用程序架构,并潜在地提高开发速度,数据运营团队投入了大量精力来自动化和简化管理数据库架构。

我们使用我们现有的工具 Git、Buildkite CI 和 pt-online-schema-change 以及另外一个工具 Skeema,将模式更改从本地开发应用到生产环境中自动化。

这个想法是将我们的单一数据库模式存储库分解为单独的模式存储库,每个数据库集群一个,并允许开发人员在他们熟悉的环境中进行自己的模式更改。 我们还希望设置合理的护栏,以帮助开发人员寻求额外的帮助,以进行大型、复杂或具有潜在破坏性的架构更改。

Skeema 是一个 CLI 工具,它使用 SQL 以声明方式管理 MySQL 模式。

它可以为数据库中的每个表生成数据定义语言 (DDL),并将 DDL 导出到本地文件系统,以便通过 Git 与跟踪存储库集成。 Skeema 可以将 Git 存储库中的 SQL 文件与实时 MySQL 数据库进行比较,并将这些差异输出为 DDL 语句。

它还可以配置为使用 Percona 的 pt-online-schema-change 工具并格式化必要的 pt-online-schema-change 命令,以将正在运行的 MySQL 数据库的模式与 Git 存储库中定义的模式相匹配。

Skeema 还能够在多个环境中管理模式,例如本地、测试和生产环境,每个环境具有不同的配置。 最后,它可以很容易地适应基于拉取请求的工作流程。

创建单独的 MySQL 数据库模式存储库将打破我们当前的单一 db-schema Git 存储库,并允许不同团队的开发人员在他们自己的存储库而不是共享存储库 (db-schema) 中管理其应用程序的 MySQL 模式。

为每个数据库模式拥有一个单独的存储库将为应用程序开发团队提供更大的自主权。 这消除了将所有模式更改协调到严格的时间表的需要,并允许根据应用程序团队的需要将更改转移到生产中。

自动化这个过程的一个重要组成部分是 Buildkite 的 CI 管道。 我们创建了一个管道:

  • 检查 SQL 语法错误
  • 使用数据库模式的当前主分支创建测试 MySQL 服务器,并测试拉取请求 (PR) 中更改的应用
  • 检查差异并将 PR 更改应用到我们的测试 MySQL 环境
  • 检查差异并将 PR 更改应用到我们的暂存环境,并从生产环境输出一些表统计信息

生产输出统计数据是磁盘上的表大小和估计的行数。 这些统计信息可以帮助确定架构更改是否会导致某种程度的服务中断并可能需要特殊处理。 将 PR 合并到 master 后,buildkite 管道会检查 master 分支与生产中运行的内容之间的差异。

如果差异是 PR 的预期更改,开发人员可以取消阻止最后一步,Skeema 将更改应用到生产 MySQL 数据库集群。 这些步骤中的每一个都是一个阻止步骤,需要负责所请求更改的工程团队的批准,然后才能进入下一步。

就护栏而言,我们已将 Skeema 配置为默认情况下不允许在生产中进行破坏性架构更改。

在我们的测试和暂存环境中允许进行破坏性更改。

我们还将 Skeema 配置为使用 pt-online-schema-change 进行架构更改。 这是 DataOps 团队熟悉的模式更改工具,并且已在 SendGrid 中使用多年。 我们为 pt-online-schema-change 开发了一组合理的选项,以在复制落后或数据库中的活动线程过多时回滚其更改。

以这种方式配置 Skeema 消除了 DataOps 团队成员对应用程序手动步骤和手动编码 pt-online-schema-change 命令的潜在错误。

通过添加程序化护栏,各个团队可以负责管理他们的 MySQL 数据库模式,并将这些更改应用到具有相对安全性的预生产和生产环境中。 如果防护栏被击中,架构更改将失败并回滚。 架构更改失败的原因将输出到构建日志以供进一步审查。

允许开发人员将他们的更改从笔记本电脑上的本地测试引导到生产环境,极大地增强了开发人员的自主权和支持其应用程序的数据库的所有权。 Skeema 的自动化和集成到我们的 MySQL 数据库管理流程中轻松涵盖了我们大约 90% 的一般模式更改管理任务。

大多数架构更改用于添加列、更改枚举字段、更改默认值和添加索引。 其余 10% 的模式更改处理大型表、非常活跃的数据库或分区表的特殊情况。 在这篇文章中,Skeema 还没有处理对分区表进行模式更改,但我听说这是一个经常被要求添加的内容,并且 Skeema 的开发人员正在积极寻求帮助来实现该功能。

将 Git、pt-online-schema-change、Skeema 和 Buildkite CI 管道相结合,为 MySQL 数据库模式更改带来了可靠、可重复的编程过程。 它使开发人员能够安全地管理其数据库的架构并控制将功能和修复部署到生产环境的速度。

在 Skeema 和 pt-online-schema 更改的配置文件中包含适当的护栏,为开发人员实施模式更改提供了一种信心度量,并在这些护栏被击中时就继续进行模式更改的可能方式提供有价值的反馈。

数据运营团队仍然可以帮助那些无法应用此流程的剩余 10% 的案例,并将致力于开发其他工具以在未来增强此流程。