Manila/design/manila-generic-groups
目录
Manila 通用组
执行摘要
Manila 需要一种分组结构,就像共享一样,是一种一级原子数据类型。我们使用 CG 的经验表明了添加分组能力所涉及的复杂性,但还有其他用例,例如迁移、复制和备份,在这些用例中,某些存储控制器只能对共享组提供这些功能。CG 还突出了高级功能的不良影响,而供应商支持的潜力相对较小。并且为每个新功能添加新的分组结构在技术上不可行。上述所有问题都可以通过通用组来解决,我们认为这是对 Manila 原始架构的一个干净的扩展。
一个棘手的矩阵
Manila 处于其发展的一个令人兴奋的时刻,所有简单的功能都可用,社区专注于添加高价值的功能,例如迁移、复制和一致性组。这些功能都有实验代码可用,但很少考虑这些复杂功能不仅要相互交互,还要与以后添加的任何其他功能进行交互的明显需求。更深入地看,很明显,这些功能中的每一个都有局限性,可以通过单个架构增强来解决。
一致性组
一致性组 (CG) 是 Manila 中唯一对一组共享进行操作的结构。对于某些人来说,CG 意味着存储控制器保证有序写入,而对于其他人来说,CG 是一种在特定时间点对一组共享进行一致快照的机制。具有任一属性的组本身可能具有价值,但 CG 的实现并未区分它们。
CG 是一种高度专业化的结构,具有专用的 CLI 命令、REST API、数据库表、调度器过滤器和驱动程序 API,总计超过 9900 行代码。这些代码中没有一个可以用于其他任何用途,并且 Manila 的其余部分对 CG 没有任何了解。更糟糕的是,尽管 CG 功能非常复杂,但只有少数存储后端可以支持它,因此代码与价值的比率非常低,并且 CG 的可用性有限确保了云之间的用户体验不一致。
复制
复制是另一个高价值功能,Manila 的实现可以说是干净且灵活的,但目前没有核心能力来复制一组共享。迭代地实现该功能似乎是合理的,从复制单个共享开始。然而,一直以来都 tacitly 承认某些后端可能无法复制单个共享,即使这些相同的后端如果以某种方式构成组,则有可能复制一组共享。
遵循 CG 建立的先例,一种方法是引入“复制组”,从而可以一起复制多个共享。但这将引入另一组过于专业化而无法用于其他用途的 API、表等。
另一种方法可能是将 CG 定义为复制的分组单元,但这没有意义,因为一致性组(无论我们如何定义它们)和复制是不同的功能,不应为了定义或实现的便利性而人为地捆绑在一起。
迁移
正如某些后端可能只能以组的形式复制共享一样,可以推断出这些后端也可能需要以组的形式迁移共享。并且在 CG 的情况下,单独迁移 CG 成员没有意义;必须移动整个组,这要求迁移引擎了解 CG。
考虑以下合理的用例
- 复制一致性组
- 对复制组进行快照
- 迁移复制组
- 在一致性组中重新调整共享类型
- 在复制组中重新调整共享类型
- 备份一致性组
- 备份复制组
- 将通用策略应用于一组共享
在当前路径上,支持矩阵有一个专门用于功能的维度,因此每个功能都必须被编码为可以与每个其他功能互操作。这很快就会变成一个支持和测试噩梦,并且随着未来添加更多功能,它会变得呈指数级复杂。
从根本上说,问题在于我们在没有底层架构框架的情况下添加功能。为了摆脱这个矩阵,我们必须退一步并重新思考一些事情。
一个简单的解决方案
因此,为了找到一个解决方案,让我们列举一下我们所拥有的
- 由共享类型控制的受支持操作的原始对象(共享),该类型因后端而异
- 一个非常具体的组对象 (CG),后端支持潜力有限
- 许多用户根本无法使用的 API(CG 等),并且似乎被移植到项目中
我们希望拥有什么
- 一个统一的 API 和用户体验,无论后端如何,变化都尽可能小
- 一种干净的方式来分组共享,以便我们可以执行 CG、多对象复制、迁移等。
我们如何到达那里?
- 普遍可用的原始对象组,其受支持的操作因后端而异
就像 Manila 有“共享”一样,它也应该有“共享组”。在最简单的情况下,与 CG 不同,共享组不应保证任何专门的操作。相反,它应该仅仅构成一个原子 Manila 数据类型,几乎任何 Manila 操作都可以在其上使用。例如,给定一个共享组,用户应该能够在 Manila UI 中选择该组并调用诸如快照、克隆、备份、迁移、复制、重新调整类型等功能。
在一般情况下,组操作由共享管理器层(或潜在的通用共享驱动程序超类)处理。例如,在组上调用“快照”会导致共享管理器单独对每个组成员进行快照。生成的组快照对象可用于创建新组,类似于 CG 快照的实现方式。
这种方法有很多优点。无论后端多么简单,每个驱动程序都可以利用组的可管理性优势。用户体验是统一的,因为无论存在哪些后端,组始终可用,并且几乎 Manila 上可用的所有操作都可用于组。
当然,功能丰富的后端希望添加他们的秘诀,无论是 CG、基于组的复制还是其他可能更容易/更便宜/更快地对共享组执行的内容。这给我们带来了相关的想法。
就像 Manila 有“共享类型”一样,它也应该有“共享组类型”。任何可以以优势方式执行组操作的驱动程序都可以将此报告为组功能,例如
- 有序写入
- 一致的快照
- 组复制
- 组备份
- 组修改
与共享类型一样,云管理员预定义共享组类型,这些类型可以包含与后端报告的组功能相对应的额外规格。管理员还指定给定组类型可以包含哪些共享类型。创建组时,用户指定组类型和共享类型,然后调度器将在匹配指定共享和共享组类型的后端之一上创建该组。
当组操作(例如“快照”)进入共享管理器时,管理器会检查其驱动程序是否提供该操作的优势实现。如果不是,则管理器将自行处理工作流程,如上所述。但是,如果是,则管理器会将工作流程路由到其驱动程序以完成。
这种方法的优点显而易见。开发和测试得到了简化,因为不需要为每个功能定义和测试一组不同的组管理 API,也不需要测试每种功能的每种组合。Manila 不会变成一个 N-by-N 相互交互的功能矩阵,而会变成一个 N-by-2 操作矩阵,这些操作可以调用到单个共享或共享组上。用户和管理员已经熟悉共享类型,因此引入共享组类型似乎是相同基础概念的自然而一致的演变。
矩阵将如下所示
| 共享操作 | 共享组操作 |
|---|---|
| 创建(卷类型) | 创建(卷类型、组类型) |
| 删除 | 删除(组,可选地所有成员) |
| 快照 | 快照(可能是 CG 快照) |
| 从快照/克隆创建 | 从组快照/克隆组创建 |
| 复制 | 复制 |
| 备份 | 备份 |
| 重新调整类型 | 重新调整类型 |
| 迁移 | 迁移 |
| 扩展/缩小 | 不适用 |
Manila 实现计划
在 Manila 中实现通用组应该是一个简单的步骤系列
- 实现通用组。因为我们已经做了 CG,所以我们已经知道代码库的哪些部分必须更改才能支持任何类型的组。因此,最简单的方法是修改 CG 代码将其转换为通用组功能。
- 通过复制和自定义共享类型代码来添加共享组类型功能。
- 增强调度器以根据共享组类型放置组。与 #1 一样,这已经受 CG 项目的影响。
- 在共享管理器中实现组快照,以演示任何驱动程序中的组快照。
- 将组快照连接到 CG 功能驱动程序,以演示新框架中的 CG 功能。
- 更新 Tempest 以涵盖以上所有内容。
- 更新 Manila 客户端以将 CG 更改为共享组。
- 增强 Manila 客户端以支持共享组类型。
- 将共享组支持添加到 Horizon。我们从未在 Horizon 中构建 CG 支持,因此这项全新工作现在具有更广泛的吸引力和适用性。
- 随着时间的推移添加其他组操作(迁移、复制、重新调整类型、克隆……)。此时,新的组功能成为易于增量添加的垂直切片。
因为我们最近才将 CG 实现为实验功能,所以我们可以自由地替换该代码而无需弃用或升级考虑。步骤 1-8 将使 Manila 与 Liberty 中添加的 CG 功能达到平价,只需要几周的人力,并能更好地为 Manila 的长期演进和可维护性做好准备。
实现细节
有一些事情需要注意,其中一些已经在 CG 工作期间解决了。
组是 Manila 中的一级对象,对组的操作被视为原子操作。为了尽可能地支持更多后端,Manila 仍然会维护组和成员快照的 DB 对象,就像 CG 所做的那样。
组的功能都将是公共额外规格,类似于共享类型中的 snapshot_support。用户需要知道组可以做什么。
一些操作,例如扩展和缩小,本质上仅适用于单个共享。从理论上讲,可以应用扩展到组,增加每个成员的大小,但这似乎不太可能使用。
任何此类操作都必须仍然可用于组成员,并且诸如对组成员进行快照之类的操作可以允许,但迁移或复制之类的操作仅在组级别可用,而不是在其成员上。
组限制为单个后端。允许跨后端的组在理论上是可行的,但这需要从 API 层到异步事件总线上的多个共享管理器的操作扇出,这将导致复杂的状态管理和同步,而带来的运营收益却很少。
与 Manila CG 一样,驱动程序可以选择将组限制在池或整个后端的范围内。已知池是某些后端的数据移动单元(即复制或迁移),因此我们认为驱动程序需要这种灵活性。
- 与 CG 的实现不同,组类型可以支持多种共享类型,但组只能包含单一类型的共享。可以稍后发布中重新审视此限制,但它可以避免许多挑战
- 组中存在多种共享类型,潜在的共享/组组合数量会变得更大,并且更有可能请求无法调度的组。
- 操作员必须测试和支持所有共享/组组合。
- 迁移变得更加复杂,尤其是在组跨越池的情况下,因为目标必须支持相同的组和共享类型组合。
- 复制也受到影响。
重新调整类型变得奇怪,如果只有一些而不是所有组成员必须迁移。
有人指出,额外规格倾向于被视为 AND 操作,其中所有功能都必须可用于后端才能被选择。即使后端可以复制组或对组进行一致的快照,它可能也无法在同一组上执行这两个操作。但是,这个问题已经存在于共享类型中,并且没有成为一个严重的问题。创建类型是管理员操作,并且管理员有责任了解正在使用的后端的capabilities,并相应地创建共享类型和共享组类型。
请注意,本提案明确不涉及池或后端复制,这在根本上是不同的。对共享或共享组的操作是为租户设计的,而池或后端可以包含来自多个租户的数据。因此,池或后端操作虽然可能具有有价值的用例,但本质上是管理员操作,如果 Manila 支持它们,则会以不同的方式设计和执行。
可以设计一个 REST API,以无缝处理共享和共享组,而无需复制 API。但在 Manila 的开发过程中,现在可能为时已晚,无法彻底重新设计 API。
可能可以重载一些现有的 API 来处理共享和共享组。例如,POST /shares/{id}/action 可以接受共享或共享组的 ID,并执行正确的操作。但是,诸如 GET /shares 之类的 API 较难重载,因为单个端点将返回不同类型的对象。
最好只是根据需要复制一些 API。例如
- POST /shares --> POST /groups
- POST /shares/{share_id}/action --> POST /groups/{group_id}/action
- POST /snapshots --> POST /group_snapshots
致谢
本文档中包含的大多数分析和建议同样适用于 Cinder,它可能在令人难以置信的复杂性方面走得更远。
这份提案由 cknight 编写,并参考了马尼拉社区成员 bswartz、ameade、tbarron 和 cfouts 的意见。关于分组的 Cinder 讨论,以及 CG 对 Cinder 的开创性贡献,都启发了这份提案,这些讨论均由 xyang 主导。