携程机票前端安卓虚拟机测试集群建设实践

一、背景

在携程内部业务高频率敏捷迭代发布节奏下,线上生产服务质量需要同步快速提升。这就依赖自动化测试的覆盖率提升,测试任务执行频次提升,测试任务执行速率提升。

通过调研机票前台内部,以及携程其他事业部前台研发和测试团队,发现存在普遍共性痛点。需要清晰化解耦自动化测试体系的三层架构,解决当前核心瓶颈。

SaaS上层服务,例如UI测试,API测试,兼容性测试,稳定性测试。PaaS中层服务,例如测试用例管理,测试任务调度,测试框架驱动。IaaS底层服务,测试用例代码最终执行和测试报告输出功能。

laas底层服务,公司各事业部的前端团队普遍通过采购手机设备,组建自动化测试设备小集群方案,或者基于开发测试人员的个人测试手机进行本地测试执行工作。这两种方式都存在一些问题。

1.1 IaaS 底层服务现状问题

1)测试手机采购成本较高。需要覆盖众多系统版本,众多厂商型号,以及持续更新换代。

2)测试手机的厂商型号差异化,导致自建小型测试设备集群的技术方案和运维管理困难。并且长期运行导致手机电池老化加速,电池膨胀损坏主板芯片,甚至存在潜在火灾隐患。

3)测试手机的用例执行稳定性和规模化受限,导致PaaS及SaaS上层的测试任务集整体执行效率降低。测试用例执行需要排队等待,测试任务容易运行失败,测试任务执行总耗时长。在集中发布日或大版本发布期间,大批量集成和回归测试用例集的任务堵塞拥挤。

1.2 IaaS 底层基建不稳对业务研发的影响

1)自动化测试工作的推广普及率和覆盖率受限。开发和测试人员在自动化测试工作中,很多耗时用于分析 Failed Job 日志,重启重试测试任务,修复运行兼容性问题。

2)海量测试用例集的总运行耗时较长,导致DevOps闭环反馈流程迟缓。于是大部分团队将自动化测试任务的频率延长到每天一次,每周一次,甚至每个版本一次。

3)自动化测试落地受阻,导致研发团队的生产交付质量被迫继续依赖手工测试团队的人工密集重复执行。手工测试容易人为疏忽遗漏,以及带来研发成本的固定支出。

二、项目目标

重构IaaS底层基建系统,降低采购和运维成本,提升测试任务可靠性和性能速度。提供通用测试设备服务,无缝支持多种上层测试框架,方便全公司各种前端团队的测试框架系统低成本接入。

三、系统选型

行业方案主要有三种:公有云真机集群、私有云真机集群和私有云虚拟机集群。

3.1 公有云真机集群

公有云真机集群是指使用行业内一些公司提供的云真机服务,例如 Testin,WeTest,以及华为,三星等厂商提供的真机云测实验室等,通常按照使用时间和使用设备数量收费。

优点:无需自建,公有云真机集群的设备型号较为完备。

缺点:费用成本中等,但是通常仅支持少量几种主流成熟测试框架,公司内各团队历史积累的测试用例集迁移成本较高。并且无法支持测试任务运行时依赖的众多内网系统,例如Mock服务、SOA服务等等。导致真正可测试覆盖的场景受限,对线上生产交付的质量保障有限。

3.2 私有云真机集群

自建方式,需要采购真机设备和专用机柜,如需满足大规模测试用例集的高频率高并发执行,就要相应采购大量手机设备。

优点:真机设备的性能较好,并且可以针对性覆盖一些特殊测试场景,例如挖孔屏、折叠屏,特定厂商API等等。

缺点:设备数量决定了测试用例集合的并发执行速度,因此前期成本投入较高,只有当大量研发团队和测试用例任务接入后,才能逐渐平摊降低成本,并且始终存在设备运维更新换代的成本支出。

现状:携程机票前端自动化测试开发团队自2017年至今使用该方案实现小型测试设备集群,通过若干台Mac mini驱动管理大约20台手机真机设备。目前该方案仍然持续运维,作为私有云虚拟机集群的补充。真机设备来源于常规采购的日常开发调试工作的淘汰换置。随着使用时间增加,安卓系统更新换代,部分设备性能逐渐下降,给研发人员日常开发调试使用带来不便。于是我们就将其换置托管到自动化测试集群,发挥余热。

3.3 私有云虚拟机集群

自建方式,使用安卓虚拟机镜像(Android Virtual Device,以下简称AVD)执行测试,以此组成测试设备集群,搭配一套管理系统对其进行统一调度。

优点:投入成本低,无需采购真机,便于根据使用量进行快速扩缩容,统一标准化管理,7x24小时可用,并且可以无缝衔接各种内部测试框架和内网依赖服务。

缺点:性能较真机略低,无法满足少量特殊测试场景,无法覆盖特定厂商机型定制功能。

随着Google Android官方团队对AVD相关组件的逐步优化,其在 X86 桌面环境模拟运行ARM指令的速度大大提升,并逐步剥离其与Android Studio / SDK的耦合,更加易于独立部署。随着K8S,Docker技术的成熟与普及,Google开源了 android-emulator-container-scripts 实验性项目,使得AVD + Docker + K8S 技术方案具备高可行性。因此我们启动了该项目的研发工作。

四、系统架构

主要由三部分组成:

容器实例层:基于K8S进行AVD容器的调度、编排,AVD 容器内包含Android 模拟器及完整运行环境、驱动程序和预安装的系统依赖项,采用OVS、Neuron、Quota、Harbor组件实现网络通信、虚拟化管理、镜像存储和分发。调度管理层:Android 模拟器的创建、销毁、缩扩容、占用、释放、重启、日志排查等,以API方式提供服务。操作使用层:Android 模拟器的Web GUI可视化和CLI命令行操作使用。

4.1 容器实例层

AVD Container的调度编排,使用了内部现有的K8S管理服务,为适应AVD容器化的使用要求,K8S管理服务做了以下适配处理:

Node配置修改:开启KVM嵌套虚拟化支持K8S容器化参数修改:设置 containers securityContext privileged = true

K8S管理服务为每台AVD容器设备分配固定IP,保证在部署和启动AVD Container后,调用者可通过固定IP访问。

Node资源配置

携程App大部分是信息数据检索页面型应用场景,对于图像和音视频处理的要求不高,Node采用Intel(R) Xeon(R) CPU E5-2680 V3 @2.5GHZ 24Core 48Thread 192G Memory配置,未配置GPU显卡。

当前Node配置的特点是内存足够,CPU不足,所以考虑对CPU进行超分。虽然CPU超配可能会导致应用高并发下运行变慢,考虑到服务于测试环境,一定的性能损耗可以容忍。

超配策略的原则是在保证服务质量的同时,尽量提高资源的利用率。通过进行节点压测,分析历史真实使用数据,确定了20%超分,高并发下AVD container仍然可以正常工作。

Pod资源配置

CPU:4C

内存:8G(初始启动消耗2.9G,运行时消耗4G)

显卡:使用Google SwiftShader 软加速库,基于CPU进行图形渲染

SwiftShader介绍

SwiftShader是Vulkan图形API12的基于CPU的高性能实现。其目标是为高级3D图形提供硬件独立性,可支持Android和Chrome(OS)构建环境。为了向用户提供最佳性能,SwiftShader 使用多种方法高效地在 CPU 上执行图形计算。动态代码生成使在运行时针对现有任务自定义代码成为可能,与更常见的编译时优化完全不同。通过使用 Reactor 简化这种复杂的方法,Reactor 是一种自定义 C++ 嵌入式语言,具有直观的命令式语法。SwiftShader 还可以单指令多线程 (SIMT) 方式使用向量运算,并结合使用多线程技术来提高 CPU 可用内核和矢量单元之间的并行性。这样可实现实时渲染,其用途包括在 Android 上进行应用串流等。

使用Airtest测试框架,选取机票流程中的常用页面,从页面渲染、元素获取,模拟点击元素这几个维度,对AVD设备和普通Android设备进行性能对比测试。

性能数据

AVD设备

普通Android真机

页面渲染(等待关键元素完成加载)

5-8秒

3-5秒

模拟点击元素

2秒

2.1秒

元素获取

600ms

500ms

综上所述,AVD设备除了页面渲染性能比真机略慢,其他维度和普通Android真机性能基本持平,能够满足日常集成测试需求。

AVD Container内运行AVD Docker镜像,镜像构建采用了Google开源的 android-emulator-container-scripts 技术方案,基于公司内部统一的Linux系统基础镜像,自定义Dockfile生成AVD Image,并上传至内部Docker Hub系统,镜像文件主要包含:

Linux操作系统Android模拟器引擎驱动程序和一些预安装的系统工具、网络服务代理

支持的Android系统版本

Android 11 (API 级别 30)Android 10(API 级别 29)Android 9(API 级别 28)Android 8.1(API 级别 27)Android 8.0(API 级别 26)Android 7.1(API 级别 25)Android 7.0(API 级别 24)Android 6.0(API 级别 23)Android 5.1(API 级别 22)Android 5.0(API 级别 21)

安卓模拟器架构图(源自Google Android官网)

由于Google官方提供的 android-emulator-container-scripts只在Debian和Ubuntu下进行过测试,我们在Centos系统下发现该脚本有诸多问题,因此沿用Ubuntu作为基础镜像。

按该脚本帮助文档中的方案激活虚拟环境,通过运行emu-docker interactive --start命令,以交互方式选择要使用的android和模拟器版本,之后将创建一个docker文件。

编辑Dockfile文件,并做以下修改:

修改from基础镜像安装并配置ssh服务,用于远程管理容器配置容器代理服务器,使APP可访问外网地址(可选)修复容器启动过程中发现的Dockfile脚本问题等

将以上内容组合在一起生成Docker镜像,这样可以创建一个完整的运行环境,在其中运行Android模拟器,使得查找系统映像,管理系统依赖以及运行安卓模拟器变得非常容易。

4.2 调度管理层

实现AVD设备的创建、销毁、扩缩容与使用管理、设备状态监控等。restAPI采用java spring boot技术实现,主要包括以下几个接口:

获取设备列表接口:获取设备状态、IP占用/释放设备接口:占用时分配可用时长,时间到达后自动释放扩容设备接口:耗时小于2分钟,单批最大50台缩容设备接口:耗时小于10秒,单批最大50台重启设备接口:耗时小于10秒

4.3 操作使用层

为方便用户使用,系统提供了UI交互界面和CLI命令行模式,以下是命令行操作示例:

获取设备列表、IP $ avd devices 设备访问连接 $ adb connect device_ip_address:5555 注:device_ip_address如上文所述由paas平台在创建AVD Docker主机时分配,该IP在测试环境和办公环境均可访问。 确认主机已连接到目标设备: $ adb devices List of devices attached device_ip_address:5555 device

五、AVD Iaas 高可用保障

AVD测试设备作为laas基础设施,稳定性是非常重要的指标,要能够为用户提供7x24的稳定保障,我们基于以下几个维度系统设计了保障策略。

1)API服务架构层面

避免单点服务,多机部署防止服务之间相互干扰,重要服务单独部署防止数据库异常导致服务不可用,增加缓存处理

2)运维层面

通用指标监控:CPU、内存、API请求量、响应时间、错误数业务指标监控:自动化使用设备量、可用设备池库存、设备申请失败率接入携程内部的报警系统,故障分钟级别响应

3)代码层面

保证代码异常不会导致服务挂掉保证服务是无状态的,可以支持水平扩展

4)设备弹性调度

防止设备不足导致任务积压排队,系统会监控任务队列情况自动扩容防止任务低谷下的设备大量闲置,系统会监控任务队列情况自动缩容

5)设备自动维护

防止设备被长期空闲占用,系统针对设备的使用情况进行定期检测,一段时间内未使用的设备,会自动收回到可用设备池,并通过IM消息通知到用户根据设备监控报警,自动拉出异常设备重启维护,确认正常后加入设备池

综合以上几点,稳定性较原先真机设备大幅提升,满足7x24小时使用的需求,SLA指标达到99%,我们也在持续努力,继续提升。

5.1 遇到的问题

由于ARM编译APP在X86架构Node运行时,会将ARM 指令都转换成 x86 指令,造成较高的性能负荷,因此与基于 x86 编译的APP相比,ARM编译APP在 x86 宿主机上的运行速度会慢很多,而且它还无法使用 x86 处理器提供的硬件加速和 CPU 虚拟化技术。为了保障应用的执行性能,我们的最初方案是将测试应用APP编译为X86模式,这样可以减少Android系统指令转换的性能开销。

随着规模的逐渐发展和更多用户场景的提出,这套方案也逐渐暴露出了一些问题:

一些APP不支持x86编译编译为x86后,少量场景运行时,底层so文件会出现异常,而同样的场景下,使用ARM编译的APP却没有问题

综合以上两个问题,我们开始寻找优化方案,可以更好的支持ARM架构编译的APP应用。

5.2 问题解决方案

Google官方在2020年开始推出Android11,新版本带来了新特性。引入Android11,可以解决ARM编译APP的性能问题。

全新的Android 11 系统映像与 ARM 兼容,它不仅允许整个系统在本机运行 x86 指令,而且还可以照常使用虚拟化技术。当应用的某个进程需要使用 ARM 二进制代码时,代码仅会在该进程内被转换成 x86 指令,其余进程将继续在 x86 环境内执行,包括 Android 运行时 (ART) 以及其它性能关键库,例如libGLES和libvulkan。除此以外,指令转换器也不会执行底层的硬件特定库,从而避免高成本的内存访问检测和相应的性能影响。经过测试,在X86服务器上基于Android11运行ARM架构APP,性能确实比之前版本提升很多,因此我们引入Android11,用户可根据APP编译类型选择合适的AVD容器。

六、AVD Iaas服务中台化

2020年携程无线公共团队提出建设无线CTest测试中台的目标,AVD Iaas作为底层基础设施方案,也加入CTest中台提供给携程各事业部使用。目前已经有15个事业部接入,总使用次数超过10000+,满足公司内多版本、多技术栈的测试任务执行和兼容性验证需求。

6.1 大规模无线UI自动化集成测试应用

无线UI自动化集成测试,是APP应用持续交付过程中绕不开的关键环节。过去在每个月交互1个版本的模式下,还能够通过增加手工测试人力勉强满足版本的验证需求,随着交付节奏的不断加快,携程内部的交付频率不断提速,如机票前台研发团队,期望提速为每周交付2次。基于此大背景下,自动化集成测试的效率是必须要解决的问题。

下图为携程机票前台研发团队的CICD流程图。

通过在特性分支和发布分支高频触发自动化测试,并设置对应的质量卡口,大部分的测试工作交由自动化完成,帮助快速发现问题,减少开发修复成本,这对自动化集成测试提出了很高的性能要求。

通过应用AVD Iaas,基于AVD容器设备的快速扩缩容能力,在项目测试开始时,系统会根据项目的case数量,动态创建、分配测试设备,保证单个项目的UI自动化集成可以在几分钟内完成。使用结束后,自动缩容回收。

最终较好的支撑了机票前台研发团队每周发布2个版本,业务快速上线的要求。

下图为使用AVD laas设备后的测试执行耗时对比。

通过按需动态扩缩容,缓解任务排队瓶颈,提高并发能力,测试用例执行耗时平均降低74%。

6.2 接入AVD laas时遇到的典型问题

在接入AVD laas的过程中,部分团队出现了UI自动化case执行通过率降低的现象。通过分析,发现主要是case代码不规范导致,比如:操作等待时长、滑动距离等操作存在硬编码,导致case代码只能在固定环境中执行通过。

为此团队总结了自动化代码规范,帮助接入方优化case代码,更好的支持不同设备环境下的稳定执行,这里就不再详细展开了。

七、总结

目前AVD laas系统已经支撑了携程绝大部分业务线在不同场景下的移动端自动化测试设备需求。我们一直在努力丰富AVD容器设备的功能场景,不断提升系统稳定性和性能,此外我们也在积极构建BDD测试执行框架、用户流量回放等自研的研发工具,通过和AVD laas形成组合拳,解锁研发活动中更多的适用场景,帮助业务团队更好的提升能效。

团队招聘信息

我们是携程机票研发团队,负责携程APP/PC端机票业务开发及创新。机票研发在搜索引擎、数据库、深度学习、高并发等方向持续不断地深入探索,持续优化用户体验,提高效率。

在机票研发,你可以和众多技术顶尖大牛一起,真实的让亿万用户享受你的产品和代码,提升全球旅行者的出行体验和幸福指数。

如果你热爱技术,并渴望不断成长,携程机票研发团队期待与你一起腾飞。目前我们前端/后台/数据/测试开发等领域均有开放职位。

简历投递邮箱:[email protected],邮件标题:【姓名】-【携程机票】-【投递职位】。

【作者简介】

Liang,携程研发总监,关注DevOps,前端&服务端质量保障、能效提升;

Tony,携程资深测试经理,关注自动化测试框架及平台类工具开发。