Cinder Volume Active/Active 支持 - 清理

https://blueprints.launchpad.net/cinder/+spec/cinder-volume-active-active-support

目前 cinder-volume 服务只能以 Active/Passive HA 方式运行。

其中一个原因是,我们没有一个概念来处理处理相同存储后端的一组节点,并且我们假设只有单个 volume 服务可以访问特定的存储后端。

基于这个前提,当前代码处理失败 volume 服务时的清理,就像没有其他服务正在使用其后端资源一样,这在 Active/Active 配置中存在问题,因为在这种配置下有其他 volume 服务正在使用这些资源。

此规范引入了一种新的清理机制,并修改了当前的清理机制,以便无论 cinder 配置如何(Active/Passive 或 Active/Active),都能正确完成清理。

问题描述

当前的 Cinder 代码仅支持 Active/Passive 配置,因此清理会考虑到这一点并相应地清理正在进行的操作的资源,但这与 Active/Active 部署不兼容。

不兼容的原因在于,volume 服务在启动时会在 DB 中查找处于操作中的资源,并且这些资源来自它们自己的存储后端 - 通过 host 字段检测 - 然后根据它们的状态进行清理。例如,一个 downloading 卷将被更改为 error,因为下载被中断,我们无法从中恢复。

使用新的任务分发机制,host 字段将包含创建资源的 volume 服务的 host 配置,但该资源现在可能被同一集群中的另一个 volume 服务使用,因此我们不能仅仅依赖这个 host 字段进行清理,因为这可能导致清理错误的资源或跳过应该清理的资源。

当使用 Active/Active 系统时,我们不能仅仅清理存储后端中的所有处于进行状态的资源,因为它们可能由其他 volume 服务处理的合法任务正在进行中。

我们暂时忘记当前如何进行清理,专注于我们必须涵盖的不同清理场景。一种是当 volume 服务“死亡”时 - 我们指的是它真正停止工作,或者它被隔离 - failover 启动另一个 volume 服务来替换它,就像它是同一个服务一样 - 具有相同的 hostcluster 配置 -,另一种场景是服务死亡并且没有其他服务接替它的位置,或者接替它的服务共享 cluster 配置但具有不同的 host

这些是我们必须解决才能支持 Active/Active 和 Active/Pasive 配置并进行适当清理的情况。

用例

具有严格要求、SLA 或其他原因的运营商,希望他们的云始终处于运行状态或具有更高的吞吐量要求,他们希望能够配置他们的部署为 Active/Active 配置,并在服务死亡时正确清理资源。

提议的变更

由于检查资源的状态和 host 字段不再足以知道它是否需要清理 - 因为 host 字段将引用创建资源的 volume 服务的 host 配置,而不是资源的拥有者,如 Job Distribution 规范中所解释 - 我们将创建一个新的表来跟踪集群中的哪个服务正在处理每个资源。

我们将这个新表称为 workers,它将包含所有正在处理可清理操作的资源,因此如果执行操作的服务崩溃,则需要清理。

当 API 或任何服务请求可清理作业时 - 例如,API 或 c-vol 服务在迁移期间可以请求卷删除 - 我们将在 workers 表中创建一个新行,其中包含我们正在处理的资源以及谁在处理它。 一旦操作完成 - 成功或不成功 - 将删除此行,以指示处理已完成,如果服务死亡,则不再需要清理。

我们不会为不可清理的操作和在可清理操作中使用但不需要清理的资源添加一行,因为这将在 DB 操作中产生显著的增加,最终会影响所有操作的性能。

这些 workers 行充当清理机制的标志,以了解在发生崩溃时是否需要检查该资源并查看是否需要清理。 对于给定的资源,一次只能存在一个可清理操作。

为了确保照顾到上述两种情况,我们将在 cinder-volume 和 Scheduler 服务中进行清理代码。

Cinder-volume 服务的清理将类似于我们当前在启动时所做的清理 - init_host 方法 - 但进行了一些小的修改以使用 workers_table,以便服务可以告诉哪些资源需要清理,因为它们在操作过程中被遗留了。 这样,我们处理了一种情况,但我们仍然需要考虑没有替代 volume 服务使用相同的 host 配置的情况,为此,我们将添加一个机制到 scheduler,它将负责请求集群中管理相同后端的其他 volume 服务来清理已失效的服务。

Scheduler 上实现的清理机制将具有手动和自动选项,手动选项需要调用者使用过滤器指定应清理哪些服务,而自动操作将让 scheduler 根据其状态和停机时间决定应清理哪些服务。

自动清理机制将由一个定期任务组成,该任务将以 service_down_time 秒的频率对已停止的服务进行采样,并将在服务停止后 auto_cleanup_checks x service_down_time 秒后,继续清理这些服务留下的资源。

由于我们可能有多个 Scheduler 服务和 cinder-volume 服务同时尝试进行清理,因此代码需要能够处理这些情况。

一方面,为了防止多个 Scheduler 清理相同的服务的资源,它们会将所有自动清理操作请求报告给 cinder-volumes,并报告给其他 Scheduler 服务,并在服务启动时询问其他 scheduler 服务哪些服务已经被清理。

另一方面,为了防止在已经开始清理的服务上进行清理并发问题,我们将使用一个时间戳发布所有清理操作,指示只有 workers 条目之前的条目才应该被清理,因此当服务开始清理资源时,它会更新条目并防止对该资源进行额外的清理操作。

workers 表中删除行将是 DB 中的真实删除,而不是像我们对其他表所做的软删除,因为操作的数量以及行数将会非常高,并且我们将对行设置约束,如果多次存在相同的资源,这些约束将不成立(有解决方法,但似乎不值得)。

由于这些将是大型且复杂的更改,我们不会默认启用任何类型的自动清理,并且需要通过使用 auto_cleanup_enabled 选项在配置中启用它,或者使用手动清理 API(使用过滤器)或自动清理 API 触发它。

即使禁用了自动清理,也可以通过 API 触发自动清理机制,因为禁用只会阻止它自动触发。

重要的是要注意,对任何资源执行“reset-state”操作将删除 DB 中任何现有的 workers 表条目。

在进行清理时,我们将确保没有其他服务正在处理该资源(声明 worker 的条目),并且 workers 条目中的数据对于给定的资源仍然有效(状态匹配),因为用户可能在此期间强制执行了对资源的另一个操作。

备选方案

有多种替代提出的更改,最有吸引力的替代方案是

  • 使用 Tooz 和一个 DLM,允许 Leader Election 来防止多个 scheduler 清理已停止的服务。 此解决方案的缺点相当大

    • 增加了对 DLM 的依赖。

    • 限制了 DLM 的选择,因为它现在需要具有 Leader Election 功能。

    • 我们仍然需要让其他 scheduler 知道 leader 何时进行清理,因为在选举新的 leader 时需要此信息来确定已停止的服务是否已经被清理。

  • 为资源上的每个操作创建新的 workers DB 条目。 此替代方案的缺点是

    • 相当大的性能影响。

    • 大大增加了清理机制的复杂性,因为我们需要将所有条目标记为正在由我们要清理的服务处理(这本身具有复杂性,因为多个 scheduler 可能会请求它或 scheduler 本身),然后查看哪些资源需要根据 workers 表进行清理,并检查是否有其他服务正在处理该资源,因为用户决定对自己的资源进行清理(例如,对正在删除的资源进行强制删除),如果没有任何其他服务正在处理该资源并且该资源具有可清理的状态,则进行清理。 在没有竞争的情况下完成所有这些操作非常复杂。

数据模型影响

创建新的 workers 表,其中包含以下字段

  • id:用于唯一标识每个条目并加快某些操作

  • created_at:用于标记 API 启动作业的时间

  • updated_at:用于标记作业上次被触碰的时间(API、SCH、VOL)

  • deleted_at:将不使用

  • resource_type:资源类型(Volume、Backup、Snapshot…)

  • resource_id:资源的 UUID

  • status:服务失败时应清理的状态

  • service_id:处理资源的 service

REST API 影响

将创建两个新的仅限管理员的 API 端点,/workers/cleanup/workers/auto_cleanup

对于 /workers/cleanup 端点,我们可以提供过滤参数,但如果未提供任何参数,清理将为所有已停止的服务发出清理消息。 但是,我们可以使用参数 service_idcluster_namehostbinarydisabled 来限制我们要清理哪些服务。

使用参数 resource_typeresource_id 也可以清理特定的资源。

在云升级期间无法触发清理,但重新启动的服务仍然会在升级期间清理自己的资源。

这两个 API 端点都将返回一个字典,其中包含两个列表,一个包含已发出清理请求的服务列表 (cleaning),另一个包含当前无法清理的服务列表,因为该集群中没有替代服务可以进行清理 (unavailable),这样调用者就可以知道哪些服务将被清理。

列表中每个服务返回的数据是 idnamestate 字段。

安全影响

通知影响

其他最终用户影响

性能影响

对可清理操作产生轻微影响,因为我们必须使用 workers 表来标记我们正在处理该资源。

其他部署者影响

开发人员影响

任何想要添加需要清理的新资源或想要添加现有资源的清理状态(新状态或现有状态)的开发人员都必须使用新机制来标记资源为可清理,添加哪些状态是可清理的,并添加清理代码。

实现

负责人

主要负责人

Gorka Eguileor (geguileo)

其他贡献者

Michal Dulko (dulek) 欢迎任何人提供帮助

工作项

  • 修改 DB 以添加新的 workers 表。

  • 实现将行添加到 workers 表。

  • host_init 更改为使用 RPC 调用进行清理。

  • 修改 Scheduler 代码以进行清理。

  • 创建 devref 解释添加清理资源/状态的要求。

依赖项

任务分发:
  • 这取决于任务分发机制,以便任何来自同一集群的可用服务都可以进行清理。

测试

针对新的清理行为的单元测试。

文档影响

文档化新的配置选项 auto_cleanup_enabledauto_cleanup_checks,以及清理机制。

文档化在主动-主动部署中 reset-state 的行为。

参考资料

HA A/A 的总体描述:https://review.openstack.org/232599

HA A/A 的任务分发:https://review.openstack.org/327283