开发之痛:稳定的测试环境,怎么就那么难

1,343 阅读14分钟

简介:开发之痛:稳定的测试环境,怎么就那么难。对于生产环境,准确、稳定最重要,我们推荐以应用为中心的基于OAM和IaC的实践方式;对于测试环境,隔离、低成本和稳定的依赖是最重要的,我们推荐基于稳定环境的隔离测试环境的实践,复用稳定环境,通过流量隔离和数据隔离来生成测试环境。通过环境建设,我们解决了研发过程中的资源冲突。

专栏策划|雅纯

志愿编辑|jimmy、吕瑞星

“对于生产环境,准确、稳定最重要,我们推荐以应用为中心的基于OAM和IaC的实践方式。

对于测试环境,隔离、低成本和稳定的依赖最重要,我们推荐基于稳定环境的隔离测试环境的实践,复用稳定环境,通过流量隔离和数据隔离来生成测试环境。“

以下是详细内容。

环境这个概念,大多数开发者都很熟悉。一个稳定、可预期、低成本的环境也是大家一致的诉求。

如下图所示,我们将环境分为生产环境、测试环境、开发环境3类。很多时候我们会把生产环境、测试环境、开发环境隔离开,就像图上的那个防火墙一样,分为线下环境和线上环境。

但在实际情况下,考虑公司体量和开发成本等诸多因素,环境的使用和划分会发生一些变化。

例如,基于成本考量,首先要保证的是生产环境,一切以提供服务为核心要务;其次是测试环境,在迁移至线上环境之前我们需要在类似于生产环境的测试环境中进行相应的验证,只有在测试环境中验证无误才可以迁移至生产环境,从而保证系统稳定的过渡。

生产环境

对于生产环境,准确、稳定的运行是相当重要的,也产生了大量的运维和治理的诉求。

如果测试环境给配置一个节点就够了,生产环境就要考虑备份、主备、分流、容灾等诸多问题,其目的都是为了保障环境的稳定运行。

准确、稳定是生产环境和别的环境的最大区别。这一特点带来了大量的运维的和服务治理的配置诉求,如何有效维护这些配置也是我们基于OAM模型、以IaC的方式来管理配置的初衷,上篇文章中有做分享。

(小编注:云效AppStack正是基于OAM的云原生应用交付平台,企业可以通过应用编排、占位符、变量等声明式定义,实现一套编排多环境差异化部署,同时基于版本和基线实现环境一键拉起、一键回滚。感兴趣的同学点击文末阅读原文可以免费使用)。

生产环境包含了很多种配置,如应用配置、应用镜像、应用运维配置、基础设施运维配置等。这些不同的配置和镜像的内容是由不同的同学关注和管理的。

开发修改代码,代码发布会改变镜像和配置;应用运维会主动修改应用运维配置;基础设施运维会修改基础设施配置。所有的配置改动都会对生产环境产生影响,带来生产环境的变化,进而可能带来风险。

因此生产环境的运维和和管理显然应该是由开发和运维来共同负责的。

测试环境

测试环境是另一类重要环境。测试环境包含两种类型:一种是集成环境,一种是预发环境。预发环境也就是类生产环境。集成环境主要用于集成测试,或者功能性的验证;预发环境主要在验收的过程中使用。

测试环境的目标是用尽可能少的资源进行独立的测试,做到隔离、复用、模拟。

例如,应用要跟外部的服务交互,如果外部服务有问题,可以在测试环境中模拟一个。

以某大数据产品为例,大数据产品大家可能会觉得环境要求太高了,没有办法做测试环境,很多的技术服务如Hive、Kafka、MySQL,对机器的要求会很高:Hive、Kafka需要有很多的机器。另外,还需要Redis做缓存、Zookeeper做服务发现。最早的时候就一套测试环境,这个显然是很低效的。如果有50个开发,共享一套测试环境,频繁冲突的情况下,几乎没有办法做测试。

为了解决这个问题,服务和应用可以做一些分层,这里分成三层。首先是公共的基础服务,比如Hive、Kafka;然后是独立的小服务,比如Redis、Zookeeper。在测试环境下,Redis和Zookeeper全部用单点是没有问题的,可以在一台虚拟机上跑起来;最上层是应用,只部署必须的应用以完成所要的测试工作。

因此,测试环境将会这么管理:首先所有的公共服务是共享的基础服务,所有的测试环境都依赖这些基础服务,各个环境的数据通过逻辑机制(如命名空间)进行隔离。在每一个测试环境会部署一套独立服务的Redis、Zookeeper。

应用层只部署所需要的应用,这样基本可以做到只消耗很小的资源就可以部署一套测试环境。很多的测试资源利用率很低,如果完整的搭一套环境的话你会发现99.99%的情况下,资源利用率都很低。

另外测试环境都应当是临时环境,这一点很重要。如果把测试环境用作长期环境,使用者会习惯某个环境就是他的,例如给环境起名字,这个环境其他人不能用,而这样会造成很大的浪费,毕竟每天使用的时间都是有限的。我们希望测试环境的资源是一个池子,可以被复用,用完即销毁。这也同时要求提高测试效率,在最短的时间内做更多的测试。

开发环境

开发环境是除了上文我们说到的生产环境和测试环境之外涉及最多的环境,比如开发、构建要用到的一些工具链,都属于开发环境的范畴。在开发环境下,我们的关注点是在本地上怎么把服务顺畅跑起来。

理想的开发环境可以跟其他的服务打通,且双向连通,因此有3个需要解决的问题:首先这个开发环境怎么访问基础环境中的服务,比如另外一个Service。第二个是怎么让其他服务访问到我们开发中的服务。第三个是怎么与其他的开发环境的请求和数据隔离。这也是我们在前面测试环境遇到的类似的问题,因此在开发环境之间也需要类似的手段,云效团队开源的kt-connect就是为了解决这个问题而设计的一个工具。

在开发环境里也会有相应的一些工具,如上图所示。大家也可以看一下,你常用的有哪些。

测试环境之痛

很多公司、很多人一提到测试环境就会说测试环境不够用、测试环境不稳定。我们在测试环境中会面临哪些挑战?尤其是分布式应用。在微服务化之后,分布式所面对的挑战也越发明显,这些挑战很多和环境有关。

例如某个应用变化没有做很好的验证,无意间进入到集成环境。这样它进入集成环境的时候本身质量是无法保证的。而在集成测试阶段,应用之间的关系非常复杂,一个服务不稳定,其他的链路都很有可能不稳定。

这也导致我们经常没有办法很好地进行日常集成测试。因为前面的过程没有办法保证,这个时候变化的应用会占用预发环境,而预发环境又是一个相对高成本的环境,不可能经常被某个人占用。于是,为了能让所有人都可以使用预发,对预发的使用将会变成很多人批量进行,这样预发变成长期环境,带来的后果就是预发的时间增长,整个开发周期和交付周期都会增长。在持续交付的流程当中,我们在测试环境当中会面临非常多的挑战:不稳定的问题、资源的问题、集成的问题等。

就目前来说,大家会遇到的比较多的测试环境的问题,大都源自服务没有进行有效的治理。服务方法多,耦合高,一旦某个服务出现问题,其他的都会受到影响。当一个环境的服务都是处在变化中时,由于随时都有不稳定的服务在部署,整个环境也将是不稳定的。

集成环境无法稳定的后果是大量的测试迁往预发,预发成为瓶颈之后又往线上迁移。任何应用最终都会用线上环境来兜底。

总结来看,测试环境主要面临如下2个挑战:

第一个是如何解决服务之间的依赖。比如A对C的强依赖,A的功能成功与否取决于C,而且C变化之后也要在A上面做相应的验证,保证C的变化是对的。

另外一个是环境本身的,主要有2点,一个是机器的稳定性,另一个是服务本身的稳定性

机器的稳定主要是:有效应对硬盘故障,网络故障等情况,做好系统的备份和容灾。

服务本身的稳定主要是:有效确保每个服务自身的可用性,因为假如一个应用的可用性是90%的话,那10个应用就是90%的10次方,导致整个的系统都会很低。

如何保证测试环境的稳定性

上文我们说到了测试环境存在的两种挑战。任何测试环境都需要保证其稳定性,降低使用线上环境的风险。那么如何保证测试环境的稳定性呢?

在测试环境中常用的实践主要有:双机部署、N+1部署、隔离环境等

例如我们一个应用至少部署两个Pod,保证至少一个在提供服务,不能让两个同时重启。确实会发生这样的情况:在某个测试环境,如果某个服务只有一个副本,该服务发生部署导致重启,会导致整个测试的不可用。在这种情况下双机部署是很好的快速解决手段,但也占用了较多的资源。

为了解决双机部署资源占用高的缺点,N+1的部署方式应运而生。采用滚动的方式逐个替换服务应用。这样你的机器就只有一个是处于变化当中,其他都是work的。这也是K8S默认的方式,一般会生成新的实例,然后再把旧的实例下掉。

为了保证测试系统的稳定性,我们需要做隔离,尽量做到除自己修改的应用,其它应用都是稳定的。

在阿里,团队引入了项目预集成环境,在阿里内部叫项目环境,这是一个隔离出来的环境,针对某一个特性在开发的阶段单独的拉取一个环境出来。

综上所述,预集成环境是隔离的,跟谁都没有关系,所依赖的其它服务都来源于稳定的环境,以保证依赖的服务都是稳定的,以便进行独立的开发和测试。

在项目早期的时候,项目预集成环境里依赖的环境还是日常集成环境,无论如何肯定比什么都不做直接放入日常集成环境里面好很多。这个时候我们发现日常集成环境还是有问题,因为在项目初期并不能保证所有的提交都会在项目预集成环境去做验证,因此会导致日常集成环境里面的依赖也可能存在很大的问题,其实本质上又回到了我们要治理日常的集成环境的事情,怎么样维持相对稳定。

针对上述问题,我们引入稳定环境的概念。既然我们将环境隔离出来了,但隔离依赖的基础环境不稳定,这个时候假如我们有一个稳定的环境是否就能解决问题了呢?

什么样的环境是稳定环境呢?就是能够发布到线上版本的环境,线上环境肯定是稳定环境,所以我们的稳定环境其实是由与线上版本一致的应用服务组成的,跟线上的服务是一致的。线上稳定,这个环境就是稳定的,所以我们就可以在这种稳定环境下再去创造隔离环境,从而保证整体稳定性。

当有了稳定的基础环境,在应用部署到生产环境之后,也同样要把它部署到基础环境中去,提供一个给测试环境作为依赖的基础环境。有了这样一个基础环境依赖,在我们应用开发时,拉出来的环境就是完全隔离的,只包含和我紧密相关的几个变化当中的应用,其余所有的依赖的服务都是从基础环境里面来的。

这里提到了基础环境的概念,那么什么是基础环境呢?基础环境是一个稳定的环境,当有了一个稳定的集成环境就可以做隔离的环境,特性测试将可以基于该隔离环境,依赖的流量也可以在隔离环境里面找。但基础环境有一定的维护成本,虽然部署成本相对来说很低,其占用的机器资源相对于一般大公司来说不是太大的问题,但对小公司可能是一个问题。但主要的成本是基础环境的维护,对基础环境进行监控并修复出现的问题,这在人力上需要一定的投入。

基础环境的维护者一般不是这个环境的使用者,所以这个时候需要有一个比较成熟的机制保证基础环境长期稳定的运行。我们开一下脑洞,如果说没有新的基础环境,哪一个环境是最稳定的呢?我们在前面把线上线下用防火墙隔开了,为什么隔开大家都知道,我们是怕安全风险,怕数据污染,但是如果我们的隔离能力做的足够好,服务路由做的足够好,监控做的足够好,安全保护做的足够好,我们是可以用生产环境来做基础环境的。

生产环境做基础环境,要解决两个重要的问题,第一个是流量隔离,流量隔离相对来说问题不太大,从以前面向资源到现在面向流量的隔离有很多现成的手段可以做。第二个是数据隔离。这个是挺大的挑战,数据形式有很多种,比如说消息队列和普通的数据库不一样,数仓又不一样,很多麻烦的问题在这里,但是具体到某一个点上都有办法解决。

小结

总结一下,对于生产环境,准确、稳定最重要,我们推荐以应用为中心的基于OAM和IaC的实践方式;对于测试环境,隔离、低成本和稳定的依赖是最重要的,我们推荐基于稳定环境的隔离测试环境的实践,复用稳定环境,通过流量隔离和数据隔离来生成测试环境。通过环境建设,我们解决了研发过程中的资源冲突,下一章我们将关注研发过程中的协作问题。

原文链接

本文为阿里云原创内容,未经允许不得转载。