列表 API 性能改进

本提案旨在改进 Tacker 中管理资源列表的检索效率 [1]

  • VNF 实例

  • VNF LCM 操作发生

  • 活动订阅

https://blueprints.launchpad.net/tacker/+spec/perf-improve-list-apis

问题描述

在 Tacker 中 API 的当前实现中,我们没有充分考虑在数据库中存在大量条目时检索数据的性能或响应时间,这在大型商业环境中很可能发生。可能会注册大量条目,并且每个条目的生命周期都很长。因此,数据库中注册了大量条目,检索目标数据需要更多时间。

根据我们简单的性能分析,查询 50,000 个条目大约需要 14 秒或更长时间。条目数量不算非常多,但响应时间对于用户来说不可接受。响应时间比预期长的主要原因不是数据库本身,而是 Tacker 中一些未充分考虑性能优化的实现。

用例

由于本提案旨在改进数据库使用或检索后的数据处理方式,因此没有额外的用例。

提议的变更

本提案的目的是进行小的更改以优化性能,并减少检索所需数据列表的总时间。虽然有几种方法可以改进从 Python 程序访问数据库,但本提案仅关注通过一些简单的评估测试选择的有效方法。

下面描述了四个问题和改进思路。

  1. 跳过转换为 TackerObject

在当前的 Tacker 实现中,从数据库检索到的每个数据条目会立即转换为 TackerObject,然后再转换为字典对象,以便按照惯例设置请求以获取列表的响应。

对于 Tacker 中的大多数用例,转换为字典对象是设置响应所必需的,但转换为 TackerObject 并非必需的,可以根据实际使用情况跳过。

  1. 重构过滤

Tacker 支持一组定义在 ETSI NFV SOL013 中的属性用于过滤 [2]。在这些属性的过滤实现中,它不会使用任何数据库过滤,而是在从数据库检索到所有条目后,在 Tacker 侧完成过滤。

  • eq

  • neq

  • nin

  • gt

  • gte

  • lt

  • lte

  • cont

  • ncont

Tacker 中的过滤成本很高,性能低于数据库的过滤。虽然它不能支持 SOL013 规范的所有属性,但仍然可以通过提供一些有限的查询条件来减少来自数据库的条目数量,然后过滤所有剩余的条目。

  1. 切断 _link 属性

为了符合 ETSI NFV 标准,_link 属性被添加到所有应该包含在结果中的条目中。在当前的 Tacker 实现中,此 _link 属性未包含在数据库中的每个条目中,而是在从数据库检索数据后才添加到条目中。

但是,添加 _link 的过程是在 Python 代码中完成的,而且成本也很高。此外,在现实中很少使用 _link 属性,可以跳过添加该属性。

  1. 修改属性检查

在属性检查中存在一些小问题,这些问题可能会降低性能,例如

  • 引用每个查询的 TackerObject 定义

  • 用于调试消息的无用日志记录

通过重构它们,我们可以期望减少总时间。

备选方案

数据模型影响

REST API 影响

安全影响

通知影响

其他最终用户影响

性能影响

我们已经多次评估了检索 VNF 实例列表的响应时间。

GET /vnflcm/v2/vnf_instances

获取响应时间的简单方法是添加如下代码的日志消息:(1)从数据库查询一批数据的时间,(2)将检索到的数据转换为所需格式的时间,以及(3)总时间。

t1 = time.perf_counter_ns()
query = context.session.query(model_cls.id, model_cls.vnfInstanceName,
    model_cls.vnfInstanceDescription, model_cls.vnfdId,
    model_cls.vnfProvider, model_cls.vnfProductName,
    model_cls.vnfSoftwareVersion, model_cls.vnfdVersion,
    model_cls.instantiationState)
result = query.all()    # to query
t2 = time.perf_counter_ns()
ret = [cls.from_db_obj(item) for item in result]   # to convert
t3 = time.perf_counter_ns()
ret = [item.to_dict() for item in ret]             # to dict
t4 = time.perf_counter_ns()
LOG.debug("### query %d, convert %d %d ###", (t2 - t1)/1000000,
    (t3 - t2)/1000000, (t4 - t3)/1000000)  # msec

以下是一些结果示例。在没有任何改进修改的情况下,查询和转换时间约为 3,000[ms],总时间为 14.12[秒]。

  • query: 2,598 [ms]

  • convert: 3,724 [ms]

  • total: 14.12 [sec]

另一方面,如果放弃转换为 TackerObject,则可以减少它。

  • query: 1,193 [ms]

  • convert: 3,233 [ms]

  • total: 9.54 [sec]

此外,在明显的情况下,总时间可以减少到大约 2 [秒]。

其他部署者影响

开发人员影响

升级影响

实现

负责人

主要负责人

工作项

修改先前“Proposed Changes”部分中讨论的每个项目的当前实现。

  1. 跳过转换为 TackerObject

将直接转换为字典对象的数据转换为跳过中间 TackerObject。

  1. 重构过滤

更改查询数据库的方式,通过为每个查询提供适当的条件来限制结果数量,并避免首先从数据库中检索所有条目。

  1. 切断 _link 属性

添加一个选项以允许排除 _link,用于不需要它的用例。我们仍然应该保留此属性以遵循 SOL 规范。

  1. 修改属性检查

  • 优化引用 TackerObject 的查询。

  • 删除用于调试消息的无用日志记录

依赖项

测试

文档影响

参考资料

历史