Noah 是一个测试环境治理平台,它以 infrastructure as code 为设计理念,通过用户自定义的可描述的环境模版快速构建和交付所需要的测试环境。它解决了DEV、QA 搭建和维护测试环境困难的痛点,为研发效率的提升起到了保驾护航的作用。
2014 年正是 Qunar 业务发展的高峰期,每天产出大量需求、需要迅速响应、快速迭代,涉及5000多次的部署、发布、上线操作。当时测试环境的搭建和维护成本是非常高的,严重阻碍了产品迭代速度。与 QA 同学沟通后发现测试环境成为瓶颈的主要原因有以下几点:
系统复杂多样,搭建一套测试环境要梳理整个系统的所有模块和组件,并厘清各模块的依赖关系、配置、部署和启动顺序。这要求操作人员对所有系统特别熟悉,事实上这是非常困难的。
审批流程耗时长,搭建环境需要走的机器审批、权限开通等都需要等待。
维护成本高,环境搭建好后,还需要维护各个服务的版本、配置、数据库,尤其是当有多套环境时维护的人力成本是非常高的 针对这些痛点,我们的工程效率团队开发了 Noah 环境管理平台,帮助业务团队走出了测试环境管理难的困境。
在讨论环境问题的时候,环境具体是什么呢?让我们重新梳理一下环境的定义,通常来说,环境是指可以运行业务应用的一个小生态集合。在 Qunar 环境一般是由 http 代理、应用、中间件、缓存和数据库五大部分组成,环境中主要是以应用为中心来构建的,通过仔细的梳理,它的画像大概是这样的:
基于上述对环境的理解,Noah 的产品设计的才更加简单、接地气。Noah 平台具有下面几个特点:
操作简单
用户可以一键构建所需的测试环境,无需人工干预。
即建即销
通过环境模版化配置,可以保证每次新建的测试环境是一致的,这样用户只需要真正使用测试环境的时候再去创建,既节省了资源又能保证测试环境的准确性。
快速交付
为了实现快速交付,我们在资源层和流程上做了优化:
对虚拟机资源进行池化,Noah 会提前创建一批虚拟机并放到资源池中,当有新建环境的请求时,直接从 KVM pool 中获取即可,省去了创建时间。
通过对应用和中间件等组件的依赖做了收集分析,构建过程中可以最大程度的并行构建,整个环境的交付时间大大缩短。那么优化后的效果有多快呢?我们拿一个业务线的环境来说明,一个包含 70 个应用、16个数据库、5个中间件的环境,它的交付时间是在10分钟以内。
环境自治
为了减少用户的维护成本,目前 Noah 实现了以下几个自治手段:
磁盘满之前自动清理。
当宿主运维时, 受影响的虚拟机可以自动漂移到其他宿主,整个过程对业务无影响。
当发现应用所在的机器异常时,会通过阻断发布的方式把问题提前暴露出来 。
测试的资源成本低
Noah 通过实现服务的软路由 (外界也称这种方式为泳道环境),可以用少量的计算资源就可以完成测试。每个业务线会维护一套稳定的公共基准环境,当有新的需求时,只需要部署需要交付的应用即可。
下面让我们从 Noah 的流程设计和系统架构来认识一下 Noah。
Noah 中把一个环境的整个构建流程抽象为一个 workflow, 包括资源锁定、资源交付、网络初始化、环境验证4个阶段。每个阶段中又拆分为多个任务,这些任务最后抽象成一个 DAG 图,它的流程如下所示:
Noah环境现在已经覆盖大部分业务线,业务线同学使用业务线模版生成多套环境以达到环境间相互隔离的目的。然而此种使用方式存在两个主要问题:
环境资源成本占用过大。
环境可用性维护成本比较大。
为了解决上述问题,Noah 通过软路由方案重用 App, 从而实现服务级虚拟化。
在上面的软路由环境中,研发人员只需要关心新的特性分支即可。
通过改造中间件、dubbo、qmq、Openesty、nginx 等组件,在请求中追加一个环境 id, 这样请求路由到组件或者应用的时候会根据环境 id 选择下游服务器地址,如果没有找到对应的环境 id, 请求自动转发到基准环境的服务。
在 Noah 环境中,每个服务单元都知道自己的路由id (即环境 id),我们会把这个环境 id 记录在 Noah 机器上的 /etc/profile.d/noah 中,程序默认会读取这个值。
每个服务单元,在启动时获取自己的路由id 并上报路由id。
服务调用发起方---浏览器/app,会通过我们的辅助开发工具绑定本次的路由id。
通过Qtrace组件,将路由id逐级传递(跨进程使用协议头,mq随同msg一起持久化)。
在需要进行路由时,当前服务(dubbo consumer/ nginx/ openresty qmq broker)根据qtrace中获取到的路由id与下级待路由节点进行比对,选择路由id相同的节点路由。
软路由方案节省了成本,但是也带来了排查问题的复杂度提升,为了帮助 DEV、QA人员快速定位问题,我们的 TC 同学提供了 trace 可视化工具,通过它我们可以看到每个请求的链路,如果某个请求异常中断,在这个 trace 图中也会一眼看出来。
为了帮助 QA 解决测试环境搭建测试数据库 (mysql) 步骤繁多(申请机器、安装 mysql、开通权限、线上同步数据、数据清洗等)、测试数据维护困难的痛点,Noah 开发了基准库,可以自动的帮用户完成这些操作。
通过对线上的库创建一个基准库、并实时同步线上的表结构变更,定时同步线上的数据。
每当新建测试库时都会从基准库创建测试库,这个过程中我们也支持用户自定义数据,比如通过 sql 脚本在创建的时候自动执行。
在测试库使用过程中,测试数据的重要性是不言而喻的,因为它不容易复现的。因此我们对每一个测试库默认做了数据备份,由于数据量巨大,所以我们把这部分数据保存在了 MFS 存储上,并且成本非常低。当数据异常丢失或者宿主挂掉无法恢复时,我们就可以新建一个测试库,并从 MFS 中的备份文件恢复数据。
2019年业务高峰期每天并发构建环境数非常多,导致下载安装 mysql 遇到了瓶颈,安装时间从原来的2分钟到13分钟,甚至有些环境直接超时失败,验证影响了 QA 的测试效率。这是由于 mysql 的 rpm 包非常大,高并发下把 yum 源的带宽占满。
通过虚拟机安装的 mysql 默认磁盘大小都是10G, centos 系统和 swap 文件默认就占去了一半多,剩余的可用空间非常少,导致数据库经常异常挂掉。对于上述遇到的2个问题,通过 mysql 容器化可以完美的解决。
节省了 80 % 的机器资源 (70 个物理机)。
交付时长从分钟级降为秒级。
降低了公司 yum 源带宽的压力。
通过 consul agent 上报容器宿主的负载、磁盘空间等信息和健康检测。
当有 db 申请请求时,会对当前的宿主节点进行筛选和优选,最后会选择一个评分最高的物理节点。
在这个选出的物理节点上启动 mysql 容器, 然后把 ip + port 信息返还给用户。
KVM 资源池化技术是为了解决在大批量环境构建时虚拟机的创建速度跟不上的问题,资源池采用了空间换时间的方式来解决这个问题。
用户创建环境。
编排引擎请求 KVM Engine 模块进行资源锁定。
KVM Engine 从 KVM pool 筛选出环境所有的 KVM 资源并交付给用户。
KVM engine 的定时任务会定时对 KVM pool 进行行补充和销毁,以保证 KVM pool 中的资源充足。
上图中涉及了 KVM 的两级调度:
openstack 创建 KVM 资源时在哪个宿主上进行 KVM 创建;
Noah 在资源锁定的时候应该选择哪个宿主机上的 KVM 资源。
我们具体看下这两级调度时如何工作的。
一级调度:OpenStack 创建 KVM 时的调度是:
初步过滤 在这一步会过滤掉不符合要求的宿主机,比如 tag 标签不符合。
计算各个宿主的权重 根据宿主机的 cpu. 核数、内存等资源计算权重值,最后选出一批适合创建 KVM 的机器列表。
具体过程如下:
二级调度:Noah 在创建环境时,环境中的机器会尽量分布在不同的机器上,这里采用的是类似轮训的算法,具体过程:
用户新建环境。
编排引擎根据环境配置进行资源锁定。
从 KVM 资源池中筛选出可调度的宿主机列表。
从宿主机列表的第一个机器开始,进行资源类型匹配和锁定,如果匹配成功,下个资源从第二个机器开始进行匹配。
如果宿主机的资源匹配失败,从下一个宿主机继续匹配。
重复4-5 直到所有资源锁定完成。
经过上面的资源调度后,一个环境的 KVM 资源是均匀分布在所有的宿主机上,这样的好处是降低了宿主机故障时的影响范围。
Noah 环境中我们提供了 tomcat 、es 、mq 、 jdk 等软件的安装,并支持用户自定义软件。这些功能是用的 ops 提供的 salt 来统一管理配置的,它的特点是速度快,灵活、配置简单。
对构建部署中产生的常见问题进行分析和收敛,并最大程度的进行自愈。
目前我们的测试场景比较有限,未来希望接入更多的测试场景,比如说单元测试、接口自动化测试、性能测试等,这样可以统一整合资源、提升效率。
Noah 作为一个环境管理平台,目前对环境的可观测性做的不够好,当环境出现问题时,我们希望帮助用户缩小问题的排查范围,甚至可以直接定位问题。