译者 | 陈峻
审校 | 孙淑娟
如果说质量保证(QA)是确定产品或服务是否满足特定要求的系统过程,那么质量保证系统则是研发过程中不可或缺的一部分,它起到了确保产品质量的作用。
在本文中,我将向您介绍在开发Milvus矢量数据库(Vector Database)时所采用的QA框架,并涵盖Milvus中的主要测试模块、以及可用于提高QA测试效率的方法和工具。
一、Milvus QA系统概述
鉴于系统架构对于QA测试的重要性,QA工程师只有对系统越熟悉,才越有可能制定出合理、有效的测试计划。
Milvus架构
Milvus 2.0采用的是云原生、分布式的分层架构。其中,SDK是数据在Milvus中流动的主要入口。通过对被频繁使用的SDK开展功能性测试,我们将能够检测出Milvus系统内部的问题。除了功能测试之外,我们还应该对矢量数据库进行单元测试、部署测试、可靠性测试、稳定性测试、以及性能测试。
云原生和分布式架构为QA测试带来了便利和挑战。与本地部署运行的系统不同,在Kubernetes集群上部署和运行的Milvus实例,可以确保在与软件开发相同的环境下,进行软件测试。然而,其缺点在于分布式架构的复杂性,会带来更多的不确定性,这会导致系统QA测试的繁琐。例如,Milvus 2.0使用不同组件的微服务,会导致服务和节点数量的增加,系统出错几率的增大。因此,我们需要更加全面的QA计划,来提高测试的效率。
二、QA测试和问题管理
Milvus的QA需要对软件开发过程中出现的问题予以测试和管理。
1.QA测试
如下图所示,我们应当根据Milvus的特性和用户需求,按照优先级的顺序,开展不同类型的QA测试。
QA测试和优先级
在Milvus中,QA测试主要针对如下几个方面进行:
- 功能:验证功能和特性能否按照最初的设计工作。
- 部署:检查用户是否可以通过不同的方式(如:Docker Compose、Helm、APT、以及YUM等)部署、重装、升级Milvus的单机版和集群。
- 性能:测试Milvus中数据的插入、索引、向量搜索和查询性能。
- 稳定性:检查Milvus在正常工作负载水平下,能否稳定运行5-10天。
- 可靠性:如果出现某个系统错误时,测试Milvus是否仍然可以部分运行。
- 配置:验证Milvus在特定配置下,能否按照预期工作。
- 兼容性:测试Milvus是否兼容不同类型的硬件或软件。
2.问题管理
软件在开发过程中可能会出现许多问题。这些问题可能源于QA工程师本人,也可能来自开源社区的Milvus用户。不过,QA团队应负责找出这些问题。
Milvus中问题管理的工作流程
在创建问题时,他们首先需要进行分类。在分流的过程中,被检查出的新问题应确保带有足够多的问题详细信息,以便开发人员的确认、接受、以及尝试修复。而在修复完成之后,问题属主则需要验证其修复,判断是否可以最终关闭该问题。
三、什么时候需要QA?
一种常见的误解是:QA和开发是相互独立的。而事实是为了确保系统的质量,开发人员和QA工程师都需要通力协作,将QA贯穿整个生命周期。
将QA引入整个软件研发的生命周期如上图所示,一个完整的软件研发生命周期包括三个阶段:
- 在初始阶段,开发人员发布设计文档,QA工程师据此制定测试计划、定义发布标准、并分配QA任务。开发人员和QA工程师需要熟悉设计文档和测试计划,以便在两个团队之间共享对于发布目标、功能、性能、稳定性、错误收敛等方面的相互理解。
- 在研发期间,开发和QA测试通过持续交互,以对开发出的特性和功能进行验证,并修复来自开源社区报告的错误和问题。
- 在最后阶段,他们可以发布那些满足发布说明和标签的新版Milvus的Docker镜像。同时,QA团队还会发布关于此版本的测试报告。
四、Milvus中的测试模块
下面,让我们来详细说明Milvus中的六个测试模块:
1.单元测试
单元测试
单元测试可以协助尽早地识别软件错误,并为代码的重组提供验证标准。根据Milvus的拉式请求(pull request,PR)验收标准,代码单元测试的覆盖率应达到80%。
2.功能测试
在Milvus中,功能测试的主要目的是为了验证接口是否可以按照设计进行运行。通过围绕着PyMilvus和SDK开展,功能测试会涉及到如下两个方面:
- 测试SDK在传递正确参数时,是否可以返回预期结果。
- 测试SDK可否处理错误,并在传递错误参数时,能否返回合理的错误消息。
下图描绘了目前基于主流pytest的功能测试框架。该框架为PyMilvus添加了一个包装器(wrapper),并通过自动化测试接口进行测试。
Milvus中的功能测试框架
考虑到测试方式在共享时,部分功能需要复用,因此我们可以采用上述测试框架,而无需直接使用PyMilvus接口。此外,该框架还包含了一个“校验(check)”模块,为期望值和实际值的校验带来便利。
其tests/python_client/testcases目录中包含了多达2700个功能测试用例,并完全覆盖了几乎所有的PyMilvus接口。而且功能测试能够严格地监督每一个PR的质量。
3.部署测试
由于Milvus有standalone和cluster两种模式,因此我们可以使用Docker Compose或Helm两种重要的方法,对其进行部署。同时,在部署了Milvus之后,用户可以采取重启或升级测试两种类别。其中,重启测试是指测试数据持久性的过程,即重启后的数据是否仍然可用。升级测试则是指测试数据地兼容性,以防止在Milvus中插入不兼容的数据格式的过程。如下图所示,两种类型的部署测试可以共享相同的工作流程:
部署测试工作流程
在重启测试中,两个部署会使用相同的Docker镜像。但是,在升级测试中,首个部署会使用前一个版本的Docker镜像,而第二个部署使用的是更高版本的Docker镜像。测试的结果和数据会被保存在Volumes文件或持久卷声明中。
首个测试在运行时会创建多个集合,并且会对每个集合进行不同的操作。而在第二个测试运行时,它会重点验证已创建的集合是否仍可用于CRUD操作,以及是否可以进一步创建新的集合。
4.可靠性测试
云原生分布式系统的可靠性测试,通常采用的是混沌工程(Chaos Engineering)方法,其目的是要将错误和系统故障扼杀在萌芽状态。换句话说,在混沌工程测试中,我们有目的地创建系统故障,以识别压力测试中的问题,并在系统故障真正开始造成危害之前予以修复。在Milvus的混沌测试中,我们可以选择Chaos Mesh作为创建混沌的工具,来创建如下故障类型:
- Pod kill:模拟节点的宕机场景。
- Pod failure:测试在有一个worker节点的pod出现故障时,整个系统能否继续工作。
- Memory stress:模拟来自worker节点对大量内存和CPU资源的消耗。
- Network partition:由于Milvus能将存储与计算分离,因此系统会严重依赖各个组件之间的通信。为了测试不同的Milvus组件之间的相互依赖关系,我们需要模拟不同pod之间的通信被分区的场景。
Milvus 中的可靠性测试框架
上图展示了Milvus中可进行自动化混沌测试的可靠性测试框架。其流程为:
- 首先,通过部署配置来读取初始化Milvus集群。
- 集群准备就绪后,运行test_e2e.py以测试Milvus的各项功能是否可用。
- 运行hello_milvus.py,以测试数据的持久性。即创建一个名为“hello_milvus”的集合,用于数据插入、刷新、索引构建、向量搜索和查询。此合集在测试期间不会被释放或丢弃。
- 创建一个监控对象,该对象将启动六个线程(如下代码段所示),分别执行创建、插入、刷新、索引、搜索和查询操作。
checkers = {
Op.create: CreateChecker(),
Op.insert: InsertFlushChecker(),
Op.flush: InsertFlushChecker(flush=True),
Op.index: IndexChecker(),
Op.search: SearchChecker(),
Op.query: QueryChecker()
}
- 做出第一个断言——所有操作都能按照预期成功运行。
- 使用Chaos Mesh解析定义故障的yaml文件,将系统故障引入Milvus。例如,每五秒“杀”一次查询节点。
- 引入系统故障时进行第二次断言——判断在系统故障期间,Milvus操作返回的结果是否符合预期。
- 通过Chaos Mesh消除故障。
- 当Milvus服务恢复(即所有pod都准备就绪)后,做出第三次断言——所有操作都符合预期。
- 运行test_e2e.py,以测试Milvus功能是否可用。在混沌消除之后,一些操作可能会被继续阻塞,进而阻碍第三次断言。因此,该步骤旨在促进第三次断言,并作为检查Milvus服务是否恢复的标准。
- 运行hello_milvus.py,以加载创建的集合,对集合进行CRUP操作。然后,检查系统故障前存在的数据,在恢复后是否仍然可用。
- 收集日志。
5.稳定性和性能测试
下表描述了稳定性和性能测试的目的、测试场景和指标。
稳定性测试和性能测试会共享同一组工作流程:
稳定性测试和性能测试的工作流程
- 解析和更新配置,并定义指标。server-configmap对应Milvus的单机或集群配置,而client-configmap对应测试用例的各项配置。
- 配置服务器和客户端。
- 准备数据。
- 请求服务器和客户端之间的交互。
- 报告和显示各项指标。
五、提高QA效率的工具和方法
从模块测试部分可以看出,大部分测试的流程其实都差不多,主要是修改Milvus服务端和客户端的配置,传递API参数。当有多种配置时,不同配置的组合越是多样化,实验和测试可以覆盖的场景也就越广。因此,代码和程序的重用,对于提高测试效率显得非常关键。
1.SDK测试框架
SDK测试框架
为了加快测试进程,我们可以在原始测试框架中添加一个API_request包装器,并将其按照API网关进行设置。此类API网关将负责收集所有API请求,然后将它们传递给Milvus,以便集体接收响应,并传递回客户端。这样的设计能够使得捕获诸如参数和返回结果等日志信息,变得更加容易。此外,SDK测试框架中的checker组件也可以验证和检查Milvus的结果。所有的检查方法都可以在该checker组件中被定义。
使用SDK测试框架,我们也可以将一些关键性的初始化过程,封装到一个函数中,以削减大量繁琐的代码。还值得注意的是,每个单独的测试用例都与其独特的集合相关,从而确保了数据的相互隔离。例如,在执行测试用例时,pytest-xdist可以利用pytest的扩展,并行执行所有单独的测试用例,从而大幅提高效率。
2.GitHub Action
GitHub Action
GitHub Action会因为其以下特点,被用于提高QA效率:
- 它是与GitHub深度集成的原生CI/CD工具。
- 拥有统一配置的机器环境,并预装了包括Docker、Docker Compose等常用的软件开发工具。
- 它支持包括Ubuntu、MacOs、以及Windows-server在内的多种操作系统和版本。
- 它拥有一个提供丰富扩展和开箱即用功能的市场。
- 其矩阵能够支持并发作业,并可重用相同的测试流程,来提高效率。
除了上述特点,采用GitHub Action的另一个原因在于部署测试和可靠性测试需要独立的隔离环境,而GitHub Action非常适合对小规模数据集进行日常检查。
3.基准测试
工具为了使QA测试更加有效,我们可以使用多种工具。
基准测试工具概览
- Argo:是一套开源的Kubernetes工具,可用于运行工作流,并通过调度任务来管理集群。同时,它也可以并行启用多个任务。
- Kubernetes仪表板:提供基于Web的Kubernetes用户界面,可用于可视化server-configmap和client-configmap。
- 网络附加存储是一种文件级数据存储服务器,可用于保存常见的ANN-benchmark数据集。
- InfluxDB和MongoDB:可用于保存基准测试结果的数据库。
- Grafana:可用于监控服务器资源指标,和客户端性能指标的开源分析和监控解决方案。
- Redash:是一项能够可视化数据,并为基准测试创建图表的服务。
原文链接:https://dzone.com/articles/open-source-software-oss-quality-assurance-a-milvu