使用驱动程序提供的函数过滤和加权后端

https://blueprints.launchpad.net/cinder/+spec/filtering-weighing-with-driver-supplied-functions

Cinder 当前使用过滤器调度器在卷操作期间过滤掉不合格的后端。默认过滤器和加权器在过滤掉不合格的后端方面做得很好,但在某些情况下,它们的效果并不理想。例如,由于稀疏配置或其他高级数据操作机制,后端可能具有“可用容量”等属性,这些属性在确定要使用的最佳后端时将不再那么有用。解决此问题的一种潜在方法是合并过滤和加权(优良度)函数,这些函数可以作为调度器决策的一部分为每个后端指定。

问题描述

Cinder 调度器当前使用的默认过滤器和加权器在某些情况下无法确定最合格的后端。如果后端使用稀疏配置等高级数据操作机制,默认过滤器使用的“可用容量”属性在确定理想后端时将不太有用或准确。

另一个问题是不同的后端使用不同的指标,只有制造商真正知道这些指标是什么。这使得创建针对这些指标的全局过滤器变得困难/几乎不可能。例如,如果有一个绝对最大容量为 1000 个卷的后端阵列,如果实际使用的空间超过 75% 的总空间,则该阵列的性能会下降。还有一个最大卷大小为 500 GB。这些细节在不同供应商之间甚至在同一供应商的不同后端阵列中都可能差异很大。

用例

提议的变更

针对上述问题提出的解决方案是在驱动程序支持的统计信息中添加两个新属性。这两个新属性将是过滤器和优良度函数。以下是这两个新属性的详细信息

* filter_function -- An equation in string form that when evaluated using
                     PyParsing will be True/False.  Used by the new filter
                     to determine if a backend should be considered by
                     the scheduler.

* goodness_function -- An equation in string form that when evaluated using
                       PyParsing will be a value between 0 and 100.  Used
                       by the new filter to which valid backend is the best
                       for the scheduler to use.

只要方程有效,就可以由以下任何运算符组成

运算

类型

+, -, *, /, ^

标准数学

非、与、或、&、|、!

逻辑

>, >=, <, <=, =, ==, <>, !=

相等

+, -

符号

x ? a : b

三元运算

abs(x), max(x, y), min(x, y)

数学辅助函数

如果需要,将来可以添加新的运算符。这些运算符应该涵盖管理员需要的绝大多数方程。

当调度器尝试找到最佳主机时,它会获取每个后端驱动程序的统计信息。优良度评级最高的后端将被返回给调度器。由于可能存在平局(三个优良度评级均为 100),因此可能会有多个后端。根据管理员选择的加权器(例如容量、随机选择等),可以解决任何潜在的平局,并选择获胜的后端。

如果后端驱动程序在报告统计信息期间未返回 filter_function 和 goodness_function 属性,则新的过滤器将默认通过该后端,并为其赋予 0 的优良度。当调度器选择最佳主机时,0 将转换为“作为最后的手段”评级。

如果驱动程序选择不实现新属性,它将返回标准的统计信息,而不会进行任何更改。例如

{
  "volume_backend_name": "array_one",
  "pools": {
      [
        "pool_name": "my_pool",
        "percent_capacity_used": 25,
        "free_space": 5000,
        "n_vols": 50,
        ...
      ],
      ...
  },
  ...
}

选择实现新属性的驱动程序需要在报告统计信息期间返回这两个新属性。这里有一个例子

{
  "volume_backend_name": "array_one",
  "pools": {
      [
        "pool_name": "my_pool",
        "filter_function": "(stats.n_vols < 1000) and (volume.size < 5)",
        "goodness_function": "stats.percent_capacity_used < 75 ? 100 : 25",
        "percent_capacity_used": 50,
        "free_space": 1000,
        "n_vols": 100,
        ...
      ],
      ...
  },
  ...
}

当调用驱动程序的 get_volumes_stats 方法时,驱动程序负责确定如何为过滤器和优良度函数属性生成方程。驱动程序的一些选择是使用在 cinder.conf 中定义的值、将值硬编码到驱动程序中或根本不实现这些属性。只要满足 filter_function 和 goodness_function 属性的要求,驱动程序还可以实现其他实现方式。

以下是使用 cinder.conf 值实现方式的示例。管理员可以为每个后端设置过滤器和优良度函数属性。例如

[foo_1]
...
filter_function = "volume.size > 10 and volume.size <= 500"
goodness_function = "50"

[foo_2]
...
filter_function = "volume.size > 500"
goodness_function = "90"

新的过滤器将仅关注基于驱动程序提供的过滤器/加权函数进行过滤。如果管理员希望进行过滤功能,例如容量,则可以使用 Cinder 中可用的其他调度过滤器以及此过滤器。

总而言之,实现一个新的调度过滤器,该过滤器允许通过过滤器和优良度函数对过滤过程进行更多控制,将更经常地正确选择用于卷的最佳后端。此解决方案存在两个潜在的缺点。首先,过滤器和优良度函数的方程在被调度器使用之前不会被验证。如果在任一方程中存在拼写错误或语法错误,则在调度器评估期间失败之前不会知道。将来可以添加某种形式的启动验证来检测无效的方程。目前,一个更简单的解决方案是假设无效的过滤器函数通过。如果过滤器或优良度函数中检测到无效方程,优良度函数将默认为 0。第二个缺点是 PyParsing 将评估的方程需要充分的文档,其中显示如何使用运算符、语法等。但是,记录这些内容不应该太难。

备选方案

一种替代解决方案是在已知位置(可能是在驱动程序本身中)的文件中包含两个函数。一个函数生成 filter_function 结果,另一个函数生成 goodness_function 结果。后端驱动程序仍然会返回两个新的统计属性,但现在它们将包含所需函数的导入路径。新的过滤器将导入所需的函数并在过滤过程中使用它们。对于未实现新属性的驱动程序,也可以提供默认的基本函数。与提出的解决方案类似,对于使用这些驱动程序的后端,默认情况下将传递并赋予 0 的优良度。

自定义定义的过滤器和优良度函数的示例

def filter_function(stats, volume, qos_specs, extra_specs, **kwargs):
    # Return True or False
    return bool(evaluate((stats.n_vols < 1000) and (volume.size < 5)))

def goodness_function(stats, volume, qos_specs, extra_specs, **kwargs):
    # Return 0 to 100
    return clamp(evaluate(stats.percent_capacity_used < 75 ? 100 : 25))

驱动程序返回的统计信息现在如下所示

{
  "volume_backend_name": "array_one",
  "pools": {
      [
        "pool_name": "my_pool",
        "filter_function": "path.to.my.custom.module.filter_function",
        "goodness_function": "path.to.my.custom.module.goodness_function",
        "percent_capacity_used": 50,
        "free_space": 1000,
        "n_vols": 100,
        ...
      ],
      ...
  },
  ...
}

此解决方案的优点是可以更轻松地检查方程是否存在拼写错误和语法错误,因为它们将是 Python 代码。更容易在启动时检查这些错误。管理员可以开发和维护自定义函数的单元测试,以便在升级后管理员可以确保一切仍然正常工作。

另一个优点是 Python 是一种文档完善的语言。管理员用于创建方程的 PyParsing 运算符需要编写文档来解释如何使用各种运算符。

一个缺点是管理员需要知道如何使用 Python 函数。根据函数放置的位置,维护所有函数也是一个潜在的缺点。

此解决方案的另一个缺点是函数不是直接来自驱动程序。如果管理员创建它们,它们将不会被驱动程序更新或与之同步。驱动程序返回的值可能会随着时间的推移而变化,例如,获得许多小卷的后端可以使用优良度值来倾向于想要更大的卷。

数据模型影响

REST API 影响

安全影响

过滤器和优良度函数方程可以由管理员在 cinder.conf 中可选地设置。每个函数的方程将是使用 pyparsing 解析的字符串。管理员可以输入他们想要的任何内容。Pyparsing 应该能够过滤掉并为管理员可能输入的任何危险字符串抛出异常。

通知影响

其他最终用户影响

如果驱动程序实现了,管理员可以选择在 cinder.conf 中为后端设置过滤和优良度函数方程。

性能影响

根据给定过滤或优良度函数方程的复杂性,使用 PyParsing 进行评估时可能会有轻微的性能下降。简单的方程对性能的影响很小。

其他部署者影响

开发人员影响

后端的宿主机统计信息、额外规格、卷信息和 QoS 规格将在过滤器和优良度函数中使用。将来可能会暴露更多信息。

实现

负责人

主要负责人

leeantho

其他贡献者

kmartin

工作项

  • 使用 pyparsing 实现评估器代码。

  • 实现一个新的驱动程序过滤器,用于调度器,该过滤器将使用评估器。

  • 更新驱动程序代码,以便在报告后端的统计信息期间返回过滤器和优良度函数属性。这仅需要在驱动程序想要实现对此新过滤器的支持时发生。

依赖项

pyparsing 模块(2.0.1 或更高版本)。

测试

可以使用单元测试来验证评估器和过滤器代码,因此不需要新的 Tempest 测试。

文档影响

  • 需要文档来详细说明驱动程序公开的用于过滤器/优良度函数的属性。每个驱动程序需要提供他们拥有的属性的文档。

  • 需要文档来解释过滤器和优良度函数方程的语法。提供使用每个运算符的示例会很好。

参考资料

Pyparsing :: http://pyparsing.wikispaces.com/