飞天测试的挑战
飞天开放平台基于一个核心系统,即飞天大规模分布式计算系统(简称飞天)。飞天期望把几千台PC构成一台“超级计算机”,为上层多种不同的开放服务和云应用提供通用的分布式存储、计算和任务调度等多重功能。由此可以看出,飞天具有平台化、通用性和大规模的特性,于是,飞天测试的挑战也由此而来。
挑战一:平台软件的复杂性和互联网发布节奏之间的矛盾。
飞天包含多个复杂的分布式模块。模块本身的复杂性乘以各模块之间的协议依赖,按照传统软件开发流程计算,发布一个质量可靠的稳定版本通常需要1~2年。这样的发布节奏远远满足不了上层开放服务和云应用快速发展的需要。
对于飞天,不同的应用场景、不同的数据量、不同的请求压力、不同的机器规模,有可能在代码里面走的路径完全不一样,对系统的压力点也各不相同。无论是试图覆盖所有应用对飞天的所有用法,还是从设计出发遍历模块接口的各种组合,对测试用例设计而言都是不收敛的。那么,当测试用例剪枝无门,是否还有其他捷径?
挑战三:对于大规模生产集群上的问题如何用小规模测试集群暴露。
在阿里各地的数据中心,飞天的生产集群是上千台物理机组成的。考虑到成本,测试集群规模通常不超过生产集群的十分之一。统计数据显示,100台和1000台的分布式环境的软硬件故障率、压力瓶颈点、数据量级、网络性能都会有很大差异。常规测试方法很难在小集群上发现大规模的问题。
下面,我们来谈一下飞天测试实践当前是如何应对这三种挑战的。
分层测试和持续集成
目前,飞天底层模块的发布节奏是半年一次,上层模块的发布则更为频繁,最短可以达到三周发布一次。这样的发布节奏主要依靠分层测试和持续集成的机制。按测试层次来分,飞天测试可以分为单元测试、功能测试、系统测试、集成测试、E2E测试(端到端测试)。为了加速飞天新版本的质量收敛,飞天团队几乎每个成员都会参与到上述测试类型中——无论是开发同学,还是测试同学。
一般来说,产品只会对外部接口进行功能测试和系统测试,但由于飞天模块本身就是分布式的,每个模块都具有一个传统软件产品的复杂度,所以模块团队除了负责单元测试,也会进行功能测试和系统测试。模块团队内,开发同学除负责单元测试之外,还会承担功能测试和局部特性的系统测试,测试同学通常更专注在测试设计和模块级别的系统测试。
飞天有独立于模块的集成测试团队,集成测试主要负责两块。
一方面,通过持续集成的回归测试集来保证系统中的各个模块改动集成在一起能够很好地工作,一旦发现无法短期修复的质量回退的话,模块改动会被立刻关闭或回滚。为保证持续集成效果,不同层次的回归测试集都被尽可能自动化,并且定义合适的回归频率,模块改动在设计时也会考虑方便关闭或回滚。
另一方面,集成测试也进行平台级别的系统测试,极尽所能地对飞天进行各种严刑拷打,考察底层模块的功能、性能和系统容量,以及在极端或典型应用场景下系统的稳定性和服务可用性。
飞天新版本上线前,开放服务团队一般都会用集成测试通过的版本跑E2E测试。E2E测试的责任人需负责向应用方了解具体需求,这个需求不仅是一个对接口功能的需求,还包含了数据量的需求、机器规模的需求、吞吐率的需求、延迟时间的需求以及业务量在一天或者一周内的曲线等信息。E2E测试通常要构造近乎完整的应用场景,尽可能模拟/重现真实的数据情况和压力特征,并且要通过长时间的稳定性测试。有些上层应用还会常备试运行环境(Staging Environment)来随时做E2E测试的验证。通常,我们只有在通过了最后的E2E测试之后才能上线给应用生产集群。
为保证测试本身的质量,各层测试覆盖有不同的衡量方法。单元测试用Coverage工具来检验行覆盖和分支覆盖;功能测试一般考察功能点覆盖外,这些都是大家熟知的。此外,我们对系统测试、集成测试和E2E测试设计了一种特别的覆盖——Log Coverage。Log Coverage工具能够通过测试运行过程中飞天输出的Log信息的多少来判断测试是否有足够的覆盖率。通过拿到生产集群的Log与测试中的Log进行比较,会找到我们之前没有测试到的地方。另外,通过对代码中从未打印出的Error Log的检查,我们也可以知道有多少异常逻辑我们没有测试过。
基于监控的探索性测试和灰盒测试
如挑战二所述,测试用例的爆炸一度让我们非常纠结。我们发现无法通过黑盒测试的设计思路来穷举所有的情况,即使能设计出足够完整的测试用例,也没有足够机器、人手和时间来执行这些测试。
所幸,我们还有探索性测试,监控系统则成为我们探索方向的指引。
飞天有详细的监控系统,可以监控整个集群的各种参数,这些参数不仅是OS层面的参数,更多的是飞天模块本身通过调用我们监控系统的API来完成对自身某些指标的统计。这些统计不仅在线上系统能够起到监控报警的作用,也能给探索性测试提供依据。执行测试的人员可以通过不断改变测试的各项参数,结合这些指标的变化进行探索式的测试,一个压力测试用例在执行时可以变化出贴近应用的各种极端场景。通常,通过指标在某些压力变化下或者随着时间推移时的异常行为,测试人员会更容易找到一些深藏的Bug。另外,在平台级别的系统测试时,通过对模块内部Error Log的监控也能达到很好的效果。
探索性测试固然重要,但仅有探索,如果测试人员本身不了解系统的一些内部逻辑的话,就会出现两种情况:第一种是只验证设计好的场景,其他一些异常的情况,自己无法解释,但本身又不是验证标准,导致很多隐藏的问题最终在线上爆发;第二种像一个无头苍蝇,漫无目的地进行探索,浪费了时间,却达不到好的效果。在飞天测试中,我们要求测试人员必须从方案设计之初甚至是讨论需求时就和开发的同学在一起讨论,测试的同学需要比开发更加理解系统的设计原则。
了解分布式系统的工作原理后,测试同学会明白如何去做一个有效的灰盒测试。比如,在某个关键点加请求压力会事半功倍;在哪个时机去做测试结果断言会更方便、彻底或完整;甚至知道对一个模块进程如何注入代码,模拟重现机率很小的协议通信丢包的问题。
原文转自:http://www.programmer.com.cn/15093/