背景
信息系统上线后通常会需要迭代升级甚至重构,如何确保系统原有业务的正确性非常重要。曾经有一家叫瑞穗证券的证券公司因为一个系统bug导致了数亿美金的损失,赔掉了公司一年的利润。这样的极端例子虽然少见,但是却像达摩克利斯之剑警示着我们,那么当前系统稳定性都有哪些挑战呢?
- 系统改造升级由于回归测试不全面导致线上故障。
- 自动化脚本的编写和维护需要大量成本,枯燥单调,且覆盖率很难保证。
- 灰度测试要临近上线才能实施,且存在流量小、无有效验证手段、不能消除bug对业务影响等问题。
阿里作为一家以电商为核心的公司,交易系统和稳定性的重要性不言而喻。整个交易系统在多年的发展过程中,经历了很多业务的上下线,维护的人员也换了一波又一波,几乎没有人能梳理清楚其中的业务和代码。当它不得不面临一次全面升级的时候,其回归测试的困难度难以想象。
如何解决?
如何实现低成本高效率的自动化测试,确保线上稳定性,避免一切可能发生的线上故障呢?复制线上真实流量来进行自动化回归归测试是一个行之有效的办法。
当前支持复制流量来做自动回归的工具有网易的tcpcopy、twitter的diffy等等,但是这些工具均无法用于交易核心系统或者是非幂等接口的测试。原因是引流会导致业务脏数据,甚至影响业务的正确性。而天猫内部诞生的doom平台的出现解决了这一难题,它通过巧妙的mock机制避免了流量回放对业务数据的影响,让复制流量回归测试适用于各种Java前后台业务系统。
效果如何?
doom平台在阿里集团内部得到广泛使用。有超过28个部门的400+核心应用的接入使用,其中一些案例效果如下:
- 订单中心(tp)的重构项目,bug总数数1385个,其中80%通过引流回归发现,确保了双十一的稳定运行。同时借助回放功能,问题排查效率提升50%。日常发布回归时间从40min+缩短至15min,覆盖率得到大幅提升。
- 交易TMF2.0重构项目通过引流回归发现有效bug 800+ ,无P3以上故障。
- 天猫物流拆分项目一期、二期通过引流回归发现遗漏bug 40+,零故障上线。
- 优惠融合项目二期、三期通过引流回归遗漏bug 30+,零故障上线。
- IC中台化项目通过引流回归发现遗漏bug 40+, 零故障上线。
- 天猫优惠平台通过引流回归实现相当长一段时间的系统零故障记录。
- ...
引流回归平台介绍
什么是doom平台
doom自动回归平台是一个将一部分线上真实流量复制并用于自动回归测试的平台。 通过创新的自动mock机制不仅支持读接口的回归验证,同时支持了写接口(例如用户下单接口、付款接口)的验证。它最底层借助了java的instrument实现aop因此,目前仅支持java应用的接入使用。其原理图如下:
它与tcpcopy或者diffy的区别:tcpcopy、diffy是在应用外的网络层实现流量录制和回放的,它们只能实现一些只读页面的验证。doom是在应用内部通过aop切面编程方式实现的流量录制和回放功能,因此可以做到应用内部接口级以及http流量的回归验证,通过巧妙创新的mock机制,可实现写流量的回归验证。
应用场景
- 系统重构时,复制真实线上环境流量到被测试环境进行回归,相当于在不影响业务的情况下提前上线检测系统潜在的问题。
- 可以将录制的流量作为用例管理起来进行日常自动化归回。
优势
doom平台在天猫内部发起,经过多年发展,逐渐推广阿里内部各个BU、蚂蚁金服。那么它到底有哪些优势呢?
低成本
无需编写测试用例
一旦接入完成就可以复制线上真实流量作为用例来进行回归测试,这些流量包括用户的一次请求或者是系统间发生的一次rpc调用。一次请求或者一次调用便作为一个用例,每一个用例都会记本次请求的入参、返回结果、对外系统调用的入参和返回结果以及自定义录制的一些过程数据,因此在回放时可以重现录制执行时的现场并完成回放过程,同时通过比对来识别系统bug。
高覆盖:
业务覆盖率
通常生产环境会处理大量用户请求,只要业务场景被用户使用到,该场景的便可以被录制成为一个用例,通过一定时间的积累就可以实现很高的覆盖率,确保每一个业务都会被覆盖到。也可以通过收藏指定的场景用例作为用例集来实现精确的用例回归,提高回放执行效率。
支持中间过程的验证
要验证业务正确性往往仅校验返回结果是不够的,例如业务系统和底层业务系统的交互请求是否变化了,业务系统写数据库数据内容是否正确,业务系统发送的异步消息内容是否正确等等。针对应用的外部请求验证是doom的基础能力,doom还支持自定义任意的函数调用过程去进行验证。
支持丰富的全对象对比功能
为了减低服务端压力以及数据的保密性,对比过程是在客户端执行。比对的内容是录制的返回结果以及请求后台系统的入参。对比方式是全对象对比,也就是对象字段逐个对比。但通常情况下直接全对象对比会导致很多误报,例如服务器ip不一样、时间不一样、集合顺序不同等等都会导致对比失败。因此在全对象对比的基础上提供比对排除、无序对比支持、针对字符串的特殊转化对比等等功能来实现对象精确对比。
轻量级:
对应用代码侵入少
只需要在工程中初始化doom的一个客户端实例即可,如何实现流量拦截都是通过字节码插桩实现。当然也有人会问,既然都已经动用字节码工具了,为什么更彻底一点,做零代码改造。实际上我们完全可以做到零代码改造,但是为了安全性考虑并没有这么做。如果是在(beta)生产环境回放,那么如何保证这些字节码修改一定是生效的?如何确保数据真正不会落库?如何保证消息一定是隔离的?我们实现了一套校验机制去识别异常情况,一旦出现问题就通过客户端实例去抛出异常,避免有问题的回放机器启动从而避免对业务的影响。
零冲突接入&免代码修改升级
平台客户端所有依赖都通过独立classloader进行加载,应用classloader只需要加载很少量的api类即可,因此引入jar依赖不会对应用造成任何jar包冲突。同时也可以实现免代码修改升级,当平台配置的客户端版本升级后,客户端在初始化时会去加载最新版本的依赖文件完成版本更新,不需要修改任何应用代码。
安全性:
经受过阿里大量核心应用的检验
目前阿里内部几乎所有交易核心系统都通过doom去做引流回归测试,没有发生过一起因doom使用过程中导致的业务故障。
影响可控
只需要线上少数几台机器开启流量录制,流量的录制也支持按百分比去采样,因此即便发生问题也不会照成大面积影响。
支持生产环境流量引流到测试环境
测试环境和生产环境数据库独立,生产环境的数据在测试环境也无法查询,那么是如何支持生产环境流量在测试环境回放的呢?原因很简单,通过mock机制的存在相当于隔离了整个回放环境对下游依赖,所以不在乎下游是否生产环境,一切数据都可以mock解决。通过这种方式也解决了下游不稳定导致常规的自动化无法正常执行的问题。
负载及异常感知功能
客户端录制流量的过程会带来一定消耗,如果生产机器压力小,这种消耗可以无忽略。但是生产机器高峰期要承受巨大压力的时候,doom客户端会感知并主动停止流量录制,确保线上稳定性。另外再在接入配置过程中也难免会出现各种问题,最最要的是配置了不可序列化的对象导致异常,客户端也会对这样异常进行监控,主动停止有问题的流量的录制。
功能强大:
支持应用接口级以及http流量的引流回归测试
一般一个网站会包括前台和后台应用,前台应用通常是通过http提供给用户服务,因此用户的每次操作都会产生一次http请求,通过录制http请求可以完成前台应用的回归验证。而前台应用要实现一些业务功能需要通过rpc调用对后台应用发起请求,针对后台应用的验证就可以录制这些rpc请求流量,即通过接口级回归验证保证。
支持链路级应用的回归测试
当发生跨应用重构的时候仅仅通过一个应用的接入来验证已经不够了。可以将重构前的应用作为录制链路,将重构后的应用作为回放链路来测试,可以更好的解决多个应用重构的回归验证。
时间机器
功能
有时候录制的流量要过很长时间才能重放,或者流量是预先录制好的,在重放的时候时间间隔较长。这时对时间敏感的流程将无法正常回放或者业务回放结果和期待的必然不一致。而通过线程级的时间替换机制可以确保回放时读取到的系统时间为录制时的时间,解决时间不一致问题。
支持热部署,流量拦截配置可立即生效。
在应用刚开始接入的时候往往要进行一些接入配置,如果每次配置都需要发布新版本或者重启一次应用,这是不可接受的,因此支持在测试环境中的一些配置通过热部署方式动态生效。而线上为了稳定性考虑,不开放生产环境热部署功能。
支持流量定向(指定机器)重放,方便问题快速定位。
当我们通过doom发现系统bug的时候可以通过重放这一利器来快速复现,您只需要设置好断点,然后通过一键重放功能将流量在您指定的机器进行重放,帮助开发人员快速定位问题,当问题修复后也可以快速验证。
支持多项目支持&流量复用
对于大一点的平台往往会有很多项目同时进行,通过配置平台上的分组管理机制可以实现多个项目同时使用流量录制回放功能,也支持一份流量多项目共同使用。
支持丰富的扩展机制用于重构验证。
当应用发生重构的时候整个回放的的执行流程可能和录制时不一致,比如重构后可能会减少rpc调用用次数或者增加某些新的rpc调用,可以通过扩展自定义处理扩展去解决这种不一致的场景,例如基于已有的上下文快照去构造新增的一个rpc调用的结果,或者自己构造一个默认的返回结果甚至是允许rpc真正执行调用等等。
支持业务覆盖率分析
这里的业务覆盖率并不是通常意义上的代码覆盖率,业务覆盖率关注具体的回放验证过程覆盖到了哪些业务而不是覆盖了多少代码行。其原理是通过指定流量的业务标识字段,然后在流量回放时对业务类型进行积累得到一个总的业务类型池,当某一次回归执行时会计算本次回归执行到的业务类型占真个业务池类型的占比,当达到100%时说明已经回归完成了该接口的所有已经执行过的业务。
平台作为云服务对外开放
初衷
doom的模式可以推广使用,因此我们在阿里云的一站式研发协作产品云效上提供了doom的云服务功能,也希望开放后借助外部力量共同完善平台。
它能帮助企业在研发测试过程解决如下问题:
- 业务快速发展、项目时间紧迫,自动化脚本来不及维护导致覆盖率不高。
- 重构或者基础组件升级,影响范围很难评估,测试工作很难展开。
- 测试环境经常受下游不稳定影响,导致自动化脚本无法正常运行。
- 测试资源不足,重复回归测试单调重复。
- 无法构造线上真实数据场景,测试效果不佳。
- 很多校验点无法验证,例如通过中间件发送消息的内容,程序执行的中间过程数据等等。
平台文档&原理:接入使用指南
云服务部署方式
如图上所示,云服务提供配置管理功能,而在用户机房可以直接使用阿里云oss存储产品来实现用例或者流量的存储也可以扩展实现自定义数据存储。
图中A企业完全使用平台功能,如果平台功能不满足需求也可以像图中企业B一样,基于平台提供的录制、回放等等能力去实现自己的稳定性/回归测试平台。
展望
一种高效率的研发测试方式
试想一下,当研发人员提交一次代码集成,系统会自动引入线上真实流量或者使用历史存储的流量进行回归测试,并以报告的形式告诉他是否存在bug,本次代码提交带来的性能提升有多少,并且通过调用链路上的分析给他指出一些可优化提示,这让他能专注于新业务的研发和系统优化,不必为修改了一行老的代码而担心触发线上故障。对于测试同学只需要关注新上线的功能是否正确,而不是关注那些一遍又一遍测了无数次的旧功能,也不用维护那些沉甸甸的脚本。这样的研发测试方式将是多么惬意的事。
要实现这样愿望还有很多事情要做,也希望有更多志之士一起来完成。
- 应用接入自动化:目前需要用户手动去做一些应用变更、手动去配置流量入口,人工去分析失败用例,对于对这套机制不熟悉以及对代码不熟悉的同学来说成本较高。这样的的接入过程实际上是有规可寻,因此做到自动化接入不是不可能。
- 如何解决mock数据库后针对数据库相关逻辑的验证:是否可以实现一个快照式的数据库,可以将回放写入数据库的影响消除,或者写入另外一个相同的影子库进行数据写入验证。
- 将doom作为一个基础组件融入到集成发布系统中:用户不需要感知doom接入过程,当用户提交集成时,系统自动会把代码部署到对应的回归环境中,并且分析代码变更去触发相关流量的回归,最终将分析报表给到用户,同时在发布时会检查是否已完成自动回归,否则自动触发引流回归并等待验证无误后才允许发布上线。
其他应用场景
doom能记录系统业务执行过程的全部上下文信息,基于这些数据能够拓展出很多应用场景,例如线上问题排查时的现场还原。以及是否能利用这些丰富的数据作为基础数据仓库提供给上层做离线或者实时数据挖掘分析以及决策等等。