VTS 仪表盘数据库

为了支持可伸缩、高性能且灵活的持续集成仪表盘,VTS 仪表盘后端必须经过精心设计,并且需要深入了解数据库功能。Google Cloud Datastore 是一种 NoSQL 数据库,它提供事务性 ACID 保证和最终一致性,以及实体组内的强一致性。但是,其结构与 SQL 数据库(甚至 Cloud Bigtable)截然不同;它不是表、行和单元格,而是种类 (kind)、实体和属性。

以下部分概述了为 VTS 仪表盘 Web 服务创建有效的后端的数据结构和查询模式。

实体

以下实体存储来自 VTS 测试运行的摘要和资源

  • 测试实体。存储有关特定测试的测试运行的元数据。其键是测试名称,其属性包括失败计数、通过计数以及警报作业更新时出现的测试用例中断列表。
  • 测试运行实体。包含来自特定测试运行的元数据。它必须存储测试开始和结束时间戳、测试构建 ID、通过和失败的测试用例数量、运行类型(例如,预提交、后提交或本地)、日志链接列表、主机名和覆盖率摘要计数。
  • 设备信息实体。包含有关测试运行期间使用的设备的详细信息。它包括设备构建 ID、产品名称、构建目标、分支和 ABI 信息。它与测试运行实体分开存储,以支持一对多的多设备测试运行。
  • 性能分析点运行实体。汇总在测试运行中为特定性能分析点收集的数据。它描述了性能分析数据的轴标签、性能分析点名称、值、类型和回归模式。
  • 覆盖率实体。描述为一个文件收集的覆盖率数据。它包含 Git 项目信息、文件路径以及源文件中每行代码的覆盖率计数列表。
  • 测试用例运行实体。描述来自测试运行的特定测试用例的结果,包括测试用例名称及其结果。
  • 用户收藏夹实体。每个用户订阅都可以用一个实体表示,该实体包含对测试的引用和从 App Engine 用户服务生成的用户 ID。这允许高效的双向查询(即,针对订阅测试的所有用户以及用户收藏的所有测试)。

实体分组

每个测试模块都代表实体组的根。测试运行实体既是该组的子项,又是设备实体、性能分析点实体和与相应测试和测试运行祖先相关的覆盖率实体的父项。

图 1。测试实体沿袭关系。

关键点:在设计沿袭关系时,您必须在提供有效且一致的查询机制的需求与数据库强制执行的限制之间取得平衡。

优势

一致性要求确保未来的操作在事务提交之前不会看到事务的效果,并且过去事务对当前操作可见。在 Cloud Datastore 中,实体分组在组内创建强读取和写入一致性的岛屿,在本例中,组内是指与测试模块相关的所有测试运行和数据。这具有以下优势

  • 警报作业对测试模块状态的读取和更新可以被视为原子操作
  • 保证测试模块内测试用例结果的一致视图
  • 在沿袭树中进行更快的查询

限制

不建议以每秒快于一个实体的速率写入实体组,因为某些写入可能会被拒绝。只要警报作业和上传的速率不快于每秒一次写入,该结构就是稳固的,并保证强一致性。

最终,每秒每个测试模块一次写入的上限是合理的,因为测试运行通常至少需要一分钟,包括 VTS 框架的开销;除非测试始终在 60 多个不同的主机上同时执行,否则不可能出现写入瓶颈。考虑到每个模块都是测试计划的一部分,而测试计划通常需要一个多小时,这种情况就更不可能发生了。如果主机同时运行测试,导致对同一主机的短时突发写入(例如,通过捕获写入错误并重试),则可以轻松处理异常。

扩展注意事项

测试运行不一定需要将测试作为其父项(例如,它可以采用其他键并将测试名称、测试开始时间作为属性);但是,这将以最终一致性换取强一致性。例如,警报作业可能无法看到测试模块内最新测试运行的相互一致的快照,这意味着全局状态可能无法完全准确地表示测试运行序列。这也可能影响单个测试模块中测试运行的显示,这可能不一定是运行序列的一致快照。快照最终将保持一致,但无法保证是最新的数据。

测试用例

另一个潜在的瓶颈是具有大量测试用例的大型测试。两个操作约束是实体组内每秒一次的最大写入吞吐量,以及最大事务大小为 500 个实体。

一种方法是指定一个以测试运行为祖先的测试用例(类似于覆盖率数据、性能分析数据和设备信息的存储方式)

图 2。测试用例从测试运行派生(不推荐)。

虽然这种方法提供了原子性和一致性,但它对测试施加了严格的限制:如果事务限制为 500 个实体,则一个测试最多只能有 498 个测试用例(假设没有覆盖率或性能分析数据)。如果测试超过此限制,则单个事务无法一次写入所有测试用例结果,并且将测试用例划分为单独的事务可能会超过每秒一次迭代的最大实体组写入吞吐量。由于此解决方案在不牺牲性能的情况下无法很好地扩展,因此不建议使用。

但是,不是将测试用例结果存储为测试运行的子项,而是可以独立存储测试用例,并将其键提供给测试运行(测试运行包含指向其测试用例实体的标识符列表)

图 3。独立存储的测试用例(推荐)。

乍一看,这似乎破坏了强一致性保证。但是,如果客户端具有测试运行实体和测试用例标识符列表,则它无需构建查询;它可以改为通过标识符直接获取测试用例,这始终保证是一致的。这种方法大大缓解了测试运行可能具有的测试用例数量的限制,同时获得了强一致性,而不会威胁到实体组内过多的写入。

数据访问模式

VTS 仪表盘使用以下数据访问模式

  • 用户收藏夹。可以使用用户收藏夹实体上的等值过滤器进行查询,该实体具有特定的 App Engine User 对象作为属性。
  • 测试列表。测试实体的简单查询。为了减少呈现主页的带宽,可以在通过和失败计数上使用投影,以便省略潜在的失败测试用例 ID 的长列表以及警报作业使用的其他元数据。
  • 测试运行。查询测试运行实体需要按键(时间戳)排序,并可能按测试运行属性(如构建 ID、通过计数等)进行过滤。通过使用测试实体键执行祖先查询,读取是强一致的。此时,可以使用存储在测试运行属性中的 ID 列表检索所有测试用例结果;根据数据存储获取操作的性质,这也保证是强一致的结果。
  • 性能分析和覆盖率数据。查询与测试关联的性能分析或覆盖率数据可以在不检索任何其他测试运行数据(例如,其他性能分析/覆盖率数据、测试用例数据等)的情况下完成。使用测试和测试运行实体键的祖先查询将检索测试运行期间记录的所有性能分析点;通过还按性能分析点名称或文件名进行过滤,可以检索单个性能分析或覆盖率实体。根据祖先查询的性质,此操作是强一致的。

有关 UI 和这些数据模式在操作中的屏幕截图的详细信息,请参阅VTS 仪表盘 UI