确保共享

https://blueprints.launchpad.net/manila/+spec/ensure-share

在每次重启 manila share 服务时更新所有共享是不合理的。当前的驱动程序接口使用方式不正确,需要重写。此规范增加了解决潜在的启动缓慢问题以及处理非用户发起的共享状态变化的能力。

问题描述

Manila-share 服务具有名为“ensure_share”的共享驱动程序接口,该接口根据共享驱动程序执行对现有共享的一些操作。此方法在每次 manila-share 服务启动时调用,并且在处理完现有共享之前不会处理任何 RPC 请求。这让云管理员感到痛苦,因为每次 manila-share 服务重启都需要的时间随着共享数量的增长而增加。此外,在大多数情况下,此处理是多余的。

用例

考虑以下合理的用例

  • Manila-share 节点将被关闭以进行维护,然后在我们想要升级软件或其他操作时重新启用。在这种情况下,管理员期望服务快速启动,无论存在多少共享以及 manila 管理它们,无论它们是否更改任何配置选项。

  • 允许管理员在管理员重启服务并更改了一些配置选项或以某种方式更新存储时自动更新共享(例如:我们有一个仅 IPv4 的控制器,并且想要添加一个 IPv6 地址(任何导出位置))。

未来我们将解决以下用例

  • 允许管理员自动标记一些共享或属于特定后端的共享,作为需要“ensure”的共享。

  • 允许管理员在管理员重启服务时更新其他资源(例如:快照、共享组等)的共享服务。

  • 允许管理员更新共享,并且无需在管理员更改数组上的内容(例如:导出位置 IP)时重启 manila share 服务。(取决于其他规范)

提议的变更

为了实现此更改,我们将执行以下操作

当共享管理器启动时,它将调用驱动程序方法 get_backend_info() 以获取可能影响共享的值的字典。共享管理器将计算返回字典的哈希值,并将其与先前计算的值进行比较。如果值未更改,则将跳过 ensure_shares 逻辑,否则 ensure_shares 逻辑将正常执行,但新的哈希值将存储在 DB 中。

get_backend_info() 驱动程序方法是一个新的驱动程序方法,它将在驱动程序初始化之后但在 ensure_shares 之前调用,返回一个字典。驱动程序将完全控制要进行哈希的字典的内容。驱动程序可以包括以下任何内容

  1. 最新的 DB 迁移的 ID。管理器将添加新的 get_recent_db_migration_id 接口,以将此值提供给驱动程序。然后,此值保证在 DB 模式更改后将调用 ensure_shares。

  2. oslo 配置对象中的任何键和值。包括这些值可保证每当配置文件以影响驱动程序的方式更改时,都会调用 ensure_shares。

  3. 驱动程序内部的硬编码值,例如版本号。包括这些值允许驱动程序强制在发生代码更改时调用 ensure_shares。

  4. 从存储控制器本身收集的值。如果管理员升级或重新配置存储控制器,这将允许 Manila 检测到更改并运行 ensure_shares,从而允许 Manila 学习任何新的重要详细信息或执行任何必要的维护。

对值进行哈希的原因是 Manila 不关心旧值是什么,只关心发生了变化。从 DB 模式的角度来看,存储值的哈希值更简单。为了避免意外的哈希冲突,将使用 MD5 生成 128 位的数据。字典将按键按字典顺序排序,并且所有值都将转换为字符串,然后 UTF-8 编码为字节,并馈送到哈希算法中。

ensure_share() 方法将被一个名为 ensure_shares() 的方法取代,该方法接收一个共享列表作为输入,并返回一个模型更新字典。这是因为没有理由对特定后端(或 share_server,如果 DHSS=true)上的少于所有共享调用 ensure_share()。将所有调用合并到一个调用中可以更容易地让驱动程序实现者重用对所有共享都通用的数据。

备选方案

数据模型影响

我们将添加一个新的表和模型来存储每个后端的哈希信息。

该模型将被称为 manila.db.sqlalchemy.models.BackendInfo,并将包含 2 个列:host 和 info_hash。host 字段将只是后端的“hostname”,没有池后缀。

REST API 影响

驱动程序影响

添加驱动程序接口

def get_backend_info(self, context):
    """Get driver and array configuration parameters and return for
       assessment.
    :return A dictionary containing driver-specific info::
         {
          'version': '2.23'
          'port': '80',
          'logicalportip': '1.1.1.1',
           ...
         }
    """

用 ensure_shares() 替换 ensure_share()

def ensure_shares(self, context, shares, share_server=None)

“””调用以确保共享已导出。

驱动程序可以使用此方法更新共享的导出位置列表(如果它发生更改)。为此,应返回一个共享字典。:shares: None 或要更新的所有共享的列表。:return None 或以以下格式更新的字典

{
    '09960614-8574-4e03-89cf-7cf267b0bd08': {
        'export_locations': [{...}, {...}],
        'status': 'error',
    },

    '28f6eabb-4342-486a-a7f4-45688f0c0295': {
        'export_locations': [{...}, {...}],
        'status': 'available',
    },

}

“””

请注意,不覆盖父类 get_backend_info() 实现的驱动程序将获得父类实现,该实现将返回一个空字典,从而防止调用 ensure_shares(),这与当前行为不同。我们可以选择性地添加该方法的覆盖实现,以用于需要更频繁地调用 ensure_shares() 的驱动程序。

作为此更改的一部分,我们将确定哪些驱动程序在 ensure_shares() 中具有必需的逻辑,并以不会丢失任何功能的方式为它们实现 get_backend_info()。

安全影响

通知影响

其他最终用户影响

性能影响

此更改的效果是在重要内容未发生更改的情况下(常见情况),使 manila-share 服务启动更快。当 ensure_shares 什么也不做或共享数量很小时,效果很小,但对于具有大量共享和昂贵的 ensure_shares 操作的后端来说,效果可能非常大,将 O(n) 启动时间减少到 O(1)。

其他部署者影响

开发人员影响

强烈鼓励驱动程序实现 get_backend_info(),但不是必需的。实现 ensure_shares() 的任何驱动程序都需要更新其逻辑,不要假定每次驱动程序启动时都会调用 ensure_shares()。

最重要的是,驱动程序能够在 ensure_shares() 中实现潜在的更昂贵的操作,而不会造成严重的可扩展性问题。

实现

负责人

主要负责人

工作项

  • 使用单元测试实现核心功能

  • 将所有 ensure_share() 方法转换为 ensure_shares()

  • 在第一方驱动程序中实现 get_backend_info()。

  • 添加此功能的文档

依赖项

测试

由于在功能测试期间重启服务很困难,因此仅使用单元测试来测试此更改是实用的。

文档影响

此功能的文档将添加到开发人员参考中。

参考资料