服务于算法的工程团队的测试需求
测试的目的是为了保证在线服务的可用性、稳定性、正确性、找到并能消除系统的性能瓶颈。
后端服务的测试一般包含下面几个方面:
- 功能测试
- 性能测试(压力测试,测试cpu、内存、io)
- 稳定性测试
除此之外,服务于算法的工程团队有一种特有的测试需求,就是一致性测试,包含如下两项:
- 特征一致性验证,为了保证在线服务要保证所使用的特征传入
- 模型一致性验证,保证在线服务和离线训练的服务一致
- 打分一致性验证,在线模型打分与离线打分进行对比,主要为了保证在线模型的准确性
当前团队的开发特点
- 使用C++语言开发在线服务,少数服务由python编写
- 网络框架和协议使用 grpc/brpc/tars+protobuf
- 微服务化,没有测试工程师,由研发工程师自主把控软件质量
- 算法工程师和架构工程师,彼此分工协作,架构工程师需要向算法工程师提供简单便捷的测试工具。
因为上面前两点原因,当前团队无法使用当前业界里优秀的开源测试工具或平台,比如JMeter、iago 、Gatling、Grinder、Locust,还有阿里云的性能测试PTS等。因为这些工具或平台仅适用于http协议,无法满足当前团队使用的网络框架和rpc协议。
那行业中有没有其他公司做过类似的工具呢?有的公司在这方面进行了尝试,比如美团技术团队自有一套针对thrift的压测工具,可惜并不开源,参考https://tech.meituan.com/2016/01/08/loading-test.html。
最终团队只能自己开发测试工具。
团队测试开发的几个发展阶段
团队在从0到1开发在线服务过程中的同时,也在搭建团队自己的开发测试工具。工具不停地被完善,其中过程包含了下面3个阶段。
- 测试脚本、小工具
- 工具升级,做出流量回放工具、面向模型服务的专用测试工具等
- 通用的后端压力测试平台
测试脚本、小工具
团队初期是通过编写测试脚本,来构造测试用例。用随机数生成的方式或通过简单的参数样本集合构造请求。
压力测试则是通过编写小工具来进行模拟上游服务的大量请求。
脚本和工具虽然简陋,但满足了项目初期的测试需求。这种测试方法持续了比较长的时间,逐渐发现如下问题:
- 随机数生成的参数与实际情况差异较大;
- 随着业务复杂度的提高,请求参数越来越多,参数的组合越来越多,测试脚本变多,无法管理。
- 自动化程度低,效率不高
流量回放工具
通过拷贝线上少部分流量,落地到文件,在有测试需求时,把文件中的请求发送给待测试的服务。
这种方式存在如下问题:
- 自动化程度依然较低,效率不高,尤其测试样本的管理
- 录制的流量容易过时。模型和策略使用的特征,往往具有时效性。流量回放,特征已经产生变化。
专用测试工具
除了流量回放工具,团队也开发了专用的测试工具,比如面向运载算法模型的在线服务。
运载算法模型的在线服务是算法工程团队运维最多的服务,占用服务器达几千台,加载近百个版本的模型。模型频繁的迭代,需要最频繁的测试。
测试最多的方面为
- 特征一致性验证
- 模型的一致性验证
- 打分的一致性验证
这里测试一致性的工具有
- 在线diff工具
- 特征一致性验证工具
在线diff工具
原理是,搭建线上和测试两套环境,同时发送相同流量,验证两个环境返回的字段、打分的不同。对于打分,会统计出不同精度下的差异率。差异结果,会通过监控系统的曲线展示出来。
特征一致性验证工具
原理为,保留每次请求的特征快照。对测试环境发起线上旁路流量,测试环境也同时落下特征快照,对两处快照做join之后,对比快照的不同。
专用工具实现了白屏化、可视化,但缺少通用性。不能适用于其他模块,也难以推广给其他团队使用。
通用的压力测试平台
为了解决自动化、可视化、平台化的问题,通用的压力测试工具被提出。
依据行业内积累的经验指导,尽管专用测试工具总会比通用测试工具在便捷性和功能性上要好于通用性工具。但为了节省重复在测试工具上的开发,最大可能赋能其他团队,通用的测试工具还是有一定意义。
比较容易实现的是压力测试工具。
如何设计一套通用的压力测试工具呢?
整体流程
通用的压力测试工具的基本流程,即流量的录制和回放。
但除了基本的流量回放,需要满足下面几点。
自动化、白屏化
包含两方面:
- 流程管理的自动化
- 流量样本的存储自动化
- 进程管理自动化
前端管理页面由html+css+js实现;流程、存储、进程的管理的实现由脚本语言,比如python来完成;进程的所需的资源交由K8S调度和管理。
可视化
压测结果通过图表展现,常见的指标有:
- 最大响应时间、平均响应时间
- PV、QPS
- TP50、TP90、TP99
- 成功数、失败数、成功率
一般由时序数据库和图表展示工具实现,时序数据库可以选择使用Prometheus/indexdb等,图型展示使用grafana等。
也可以使用公司自研的数据采集和展示系统。
平台化
需要满足的需求多租户和组件化。
多租户是为了让压力测试平台供多人使用,也可以做到用户间测试资源进行隔离和共享。
组件化,是为了让通用的压力测试平台更简单地支持更多c++在线服务。具体的的实现方法如下:
- 平台定义组件的统一接口,建立调用框架。
- 不同组件依据平台的统一接口,定义自己的接口实现,并编译成为动态链接库。
- 平台通过加载组件的动态链接库,实现面向不同服务的流量录制与回放。