一、背景
在携程内部业务高频率敏捷迭代发布节奏下,线上生产服务质量需要同步快速提升。这就依赖自动化测试的覆盖率提升,测试任务执行频次提升,测试任务执行速率提升。
通过调研机票前台内部,以及携程其他事业部前台研发和测试团队,发现存在普遍共性痛点。需要清晰化解耦自动化测试体系的三层架构,解决当前核心瓶颈。
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 真机性能基本持平,能够满足日常集成测试需求。
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 命令行模式,以下是命令行操作示例:
五、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 形成组合拳,解锁研发活动中更多的适用场景,帮助业务团队更好的提升能效。
作者简介
Liang,携程研发总监,关注 DevOps,前端 &服务端质量保障、能效提升;
Tony,携程资深测试经理,关注自动化测试框架及平台类工具开发。
本文转载自:携程技术中心(ID:ctriptech)
评论