跟着小程学微服务-Mock自动化系统的原理及实现

一、前言

今天我将和大家一起探讨我们的“自动化Mock系统1.0版本”。

二、测试人员面临的测试问题

我公司目前用的是基于Dubbo的微服务改造,服务之间的调用链路冗长,每个服务又是单独的团队在维护,每个团队又在不断的演进和维护各个服务,那么对测试人员将是非常大的挑战。

测试人员每次进行功能测试的时候,测试用例每次都需要重新写一遍,无法将测试用例的数据沉淀,尤其是做自动化测试的时候,测试人员准备测试数据就需要很长时间,效率非常低。

目前接口自动化测试框架也多种多样,testng,junit,Fitnesse等,但都需要测试人员具备测试代码编写能力,如果要做好和手工接口测试一样效果的自动化测试更是需要大量的代码堆积,后期维护代码成本非常大。因此做成简单配置用例流,无需编写测试代码的系统是更贴合实际工作要求。

举个例子:拿互联网支付系统来说,某个团队新增了支付交易的需求,这时候要进行测试,测试人员除了要测试支付交易需求本身是否正确,同时也要结合上下游的服务整体进行回归测试,这时候开发人员往往在支付交易系统中采用“硬编码”的方式对上下游的系统进行“挡板”,如果测试人员对测试数据有所调整那么“挡板”也要跟着调整,同时在项目正式上线的时候,如果开发人员没有将“挡板”程序去除干净,将面临严重的线上问题。

三、Dubbo的Mock功能

1、Dubbo的Mock使用

Dubbo自带的Mock功能首先是为了做服务降级,比如某验权服务,当服务提供方全部挂掉后,客户端不抛出异常,而是通过Mock数据返回授权失败。

我们从官网上举一个例子来说明:

<dubbo:reference interface="com.foo.BarService" mock="force" />

我们可以在期望的reference标签上加一个mock="force",就可以将当前服务设置为mock。但是设置完mock属性后还没有结束,需要有一个Mock类对应我们的服务接口类。

规则如下:
接口名 + Mock后缀,服务接口调用失败Mock实现类,该Mock类必须有一个无参构造函数。

对应到com.foo.BarService的话,则创建BarServiceMock类。

public class BarServiceMock implements BarService {    public String sayHello(String name) {           // 你可以伪造容错数据,此方法只在出现RpcException时被执行
   return "容错数据";
    }
}

经过以上设置后,当调用BarService进行远程调用的话,直接请求到BarServiceMock类上面进行模拟测试。

2、Dubbo Mock的原理解析

在dubbo的配置文件中
classpath:/META-INF/dubbo/internal/com.alibaba.dubbo.rpc.cluster.Cluster
可以看到如下配置列表:

mock=com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper  
failover=com.alibaba.dubbo.rpc.cluster.support.FailoverCluster  
failfast=com.alibaba.dubbo.rpc.cluster.support.FailfastCluster  
failsafe=com.alibaba.dubbo.rpc.cluster.support.FailsafeCluster  
failback=com.alibaba.dubbo.rpc.cluster.support.FailbackCluster  
forking=com.alibaba.dubbo.rpc.cluster.support.ForkingCluster  
available=com.alibaba.dubbo.rpc.cluster.support.AvailableCluster  
switch=com.alibaba.dubbo.rpc.cluster.support.SwitchCluster  
mergeable=com.alibaba.dubbo.rpc.cluster.support.MergeableCluster  
broadcast=com.alibaba.dubbo.rpc.cluster.support.BroadcastCluster

我们可以看到配置文件中实际上有五大路由策略:

  • AvailableCluster: 获取可用的调用。遍历所有Invokers判断Invoker.isAvalible,只要一个有为true直接调用返回,不管成不成功。
  • BroadcastCluster: 广播调用。遍历所有Invokers, 逐个调用每个调用catch住异常不影响其他invoker调用。
  • FailbackCluster: 失败自动恢复, 对于invoker调用失败, 后台记录失败请求,任务定时重发, 通常用于通知。
  • FailfastCluster: 快速失败,只发起一次调用,失败立即保错,通常用于非幂等性操作。
  • FailoverCluster: 失败转移,当出现失败,重试其它服务器,通常用于读操作,但重试会带来更长延迟。

Dubbo中默认使用的是FailoverCluster策略,而在实际执行的过程中是FailoverCluster会被先被注入到MockClusterWrapper中,过程就是:

Cluster$Adaptive -> 定位到内部key为failover的对象 ->FailoverCluster->注入到MockClusterWrapper

MockClusterWrapper内部会创建一个MockClusterInvoker对象。实际创建是封装了FailoverClusterInvoker的MockClusterInvoker,这样就成功地在Invoker之中植入了Mock机制。

我们来看MockClusterInvoker的内部实现:

  • 如果在没有配置之中没有设置mock,那么直接把方法调用转发给实际的Invoker(也就是FailoverClusterInvoker)。

    String mockValue = directory.getUrl().getMethodParameter(  
          invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim();  
      if (mockValue.length() == 0 || mockValue.equalsIgnoreCase("false"))  
      {  
          //no mock  
          result = this.invoker.invoke(invocation);  
      }
  • 如果配置了强制执行Mock,比如发生服务降级,那么直接按照配置执行mock之后返回。

    else if (mockValue.startsWith("force"))  
    {  
        if (logger.isWarnEnabled())  
        {  
           logger.info("force-mock: " + invocation.getMethodName() + " force-mock enabled , url: " +  directory.getUrl());  
         }  
        //force:direct mock  
         result = doMockInvoke(invocation, null);  
    }
  • 如果是其它的情况,比如只是配置的是mock=fail:return null,那么就是在正常的调用出现异常的时候按照配置执行mock。
    try   {  
      result = this.invoker.invoke(invocation);  
    }  catch (RpcException rpcException)  {  
       if (rpcException.isBiz())  {  
           throw rpcException;  
       }  
       else  
       {  
       if (logger.isWarnEnabled())  {  
          logger.info("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : "  
       +  directory.getUrl(), rpcException);  
       }  
          result = doMockInvoke(invocation, rpcException);  
       }  
    }
3、Dubbo Mock的适用场景

Dubbo的Mock功能主要是为了做服务降级而使用的,服务提供方在客户端执行容错逻辑,在出现RpcException(比如网络失败,超时等)时进行容错,然后执行降级Mock逻辑。自身并不适合做Mock测试系统。

四、自动化Mock系统的实现

1、Mock系统的简单用例图

2、Mock系统的架构图

为了基于Dubbo实现Mock功能,需要对Dubbo源码进行一些必要的修改,通过上面的架构图我们可以看到,实际上我们正是利用了Dubbo的Filter chain过滤器链这一机制实现的,为了方便大家更好的理解,下面将简单介绍一下Dubbo的Filter机制。

2.1、Dubbo的Filter原理分析

Filter:是一种递归的链式调用,用来在远程调用真正执行的前后加入一些逻辑,跟aop的拦截器servlet中filter概念一样的。

Filter接口定义:

@SPIpublic interface Filter {     Result invoke(Invoker<?> invoker,Invocation invocation)   throws RpcException;
}

Filter的实现类需要打上@Activate注解, @Activate的group属性是个string数组,我们可以通过这个属性来指定这个filter是在consumer, provider还是两者情况下激活,所谓激活就是能够被获取,组成filter链。

List<Filter> filters =ExtensionLoader.getExtensionLoader(Filter.class).getAct ivateExtension(invoker.getUrl(),key, group);Key就是SERVICE_FILTER_KEY还是REFERENCE_FILTER_KEYGroup就是consumer或者provider

关于SPI的详细介绍请大家参考我之前写的另一篇文章http://www.jianshu.com/p/46aa69643c97

ProtocolFilterWrapper:在服务的暴露与引用的过程中根据KEY是PROVIDER还是CONSUMER来构建服务提供者与消费者的调用过滤器链,Filter最终都要被封装到Wrapper中的。

public <T> Exporter<T> export(Invoker<T>invoker)throws RpcException {return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
}   public <T> Invoker<T> refer(Class<T> type,URL url)
  throws RpcException {          return buildInvokerChain(protocol.refer(type, url),Constants.REFERENCE_FILTER_KEY, Constants.CONSUMER);
}

构建filter链,当我们获取激活的filter集合后就通过ProtocolFilterWrapper类中的buildInvokerChain方法来构建。

for (int i = filters.size() - 1; i >= 0; i --) {         final Filter filter = filters.get(i);         final Invoker<T> next = last;
   last = new Invoker<T>() {                 public Result invoke(Invocation invocation)throws RpcException {
      return filter.invoke(next, invocation);
     }
           //。。。。。。。 //其他方法
       };
 }
2.2、Mock流程介绍

注:我们在<dubbo:application name>中新加了自定义的“env=test”这样的属性配置用来标明当前环境是测试的还是正式的,用户每次通过Dubbo请求的远程服务的时候,都会首先经过我们自定义的Filter,我们自定义的Filter会首先判断当前的环境是test还是正式,如果是test的环境则直接访问Mock配置中心获取提前配置好的Mock数据并封装成用户定义的Response对象返回。

3、Mock系统的配置中心

Mock配置中心就是用户将mock数据与应用环境建立关系的系统,整个系统就像一个工作流引擎:

环境设置->应用名称设置->挡板规则设置->Facade服务接口设置->方法规则设置

  • 环境设置

注:如果尚未映射来源IP地址到环境,则点击环境列表导航链接,进入环境列表页面,点击添加,输入源IP及环境名,点击确定按钮,实现源IP到所设环境的映射。每个用户都可以建立属于自己的测试环境。

  • 应用名称设置

注:创建所使用系统的应用名称,Mock配置中心默认使用<dubbo:application name>中的名称作为应用名称。

  • 挡板规则

注:每一个挡板规则都是由一个环境名称和应用名称组成的唯一挡板,在挡板设置中选择环境名称和应用名称,并且设置挡板的有效状态。

  • Facade规则

注:每一个Facade就是一个Dubbo的服务接口类,在这里将自己的Facade名称与全路径与挡板名称对应,以标识哪些Facade服务接口类是属于哪个挡板的。

  • 方法规则

注:方法规则是用来设置每个Facade中的需要mock的方法的,可以对不同的方法设置方法执行时间、方法抛出的异常等等。

4、Mock系统的其他功能

由于不少应用项目开发完后想对其进行单独压测,而很多时候应用系统和其他业务系统形成了依赖关系,如果不布署其他应用系统则无法完成压测,为了更好的支持性能测试组进行挡板压测,Mock系统支持压测功能,而Mock系统自身也可以达到单台服务器1000TPS以上(8C8G)。(全文完)

来源:中生代技术

原文链接

时间: 2025-01-21 19:19:14

跟着小程学微服务-Mock自动化系统的原理及实现的相关文章

谢康 | 同程旅游微服务最佳实践

本文首发胖波聊架构界,微信公众号:xiaobo2as 本文概要 导言 微服务拆分的四个维度 微服务应该如何维护版本 如何从单体架构平滑过渡到微服务 结语 一.导言 同程微服务从立项到实施推广已经走过了整整两个年头,从最初的简单粗糙到今天的精细完善,接入服务数量也实现了从1到10,000+的增长. 微服务开发团队和大家一起踩过了无数的坑,最终打造了今天的DSF2.0平台.回顾爬坑记录,现整理一些爬坑心得体验供大家参考,也斗胆提出一些最佳实践以抛砖引玉. 下文将从开发者角度对微服务如何拆分, 版本管

微服务架构的理论基础 - 康威定律

概述 关于微服务的介绍,可以参考微服务那点事. 微服务是最近非常火热的新概念,大家都在追,也都觉得很对,但是似乎没有很充足的理论基础说明这是正确的,给人的感觉是 不明觉厉 .前段时间看了Mike Amundsen <远距离条件下的康威定律--分布式世界中实现团队构建>(是Design RESTful API的作者)在InfoQ上的一个分享,觉得很有帮助,结合自己的一些思考,整理了该演讲的内容. 可能出乎很多人意料之外的一个事实是,微服务很多核心理念其实在半个世纪前的一篇文章中就被阐述过了,而且

元数据如何驱动微服务报文架构?

本文讲的是元数据如何驱动微服务报文架构?,随着微服务的概念逐渐被人们接受,大家都在努力将自己的应用系统向微服务框架转型.在我们研发微服务框架的时候,就发现随着服务数量的增多,服务接口定义就需要一套统一数据标准来支撑:在对服务接口做实参的时候,频繁的且重复性的赋值让人很抓狂.本文将阐明我们面临这些问题是如何解决的. 本文目录: 一.什么是报文 二.报文为什么需要规范 三.常规的报文规范 四.微服务下的报文规范面临的问题 五.元数据驱动的微服务报文 六.技术实践 一.什么是报文? 报文(messag

融数数据基于DevOps的微服务架构演进之路

主题:互联网架构  融数数据基于DevOps的微服务架构演进之路 - 融数数据CTO  王东 讲师介绍 王东: 现任融数数据北京研发中心CTO,负责公司大数据平台.微服务框架以及DevOps平台的研发工作:  毕业于天津大学,毕业后一直从事软件相关研发和架构设计工作,曾经在普元软件任资深架构师.IBM GBS任咨询经理.亚马逊任架构师等,后加入创业公司,从事研发和管理工作:  热爱编程,喜欢钻研新技术,对于微服务.企业架构.大数据以及DevOps有浓厚的兴趣.  谈谈微服务 近年来微服务热度逐渐

微服务架构之外的选择——基于服务架构

来自ThoughtWorks的主管Neal Ford在最近的一次演讲中表达了他对企业软件系统架构转型的看法,他认为从单体架构转向基于服务的架构要比转向微服务架构来得容易.Ford在UberConf 2016大会上做了一次关于基于服务架构的演讲,基于服务架构是介于面向服务架构和微服务架构之间的一个中间地带.这里可以下载演讲幻灯片(PDF格式). 微服务架构有很多优点,不过Ford建议应该把这些优点应用在新开发的项目上.对于已经采用了单体架构的组织来说,转向微服务架构有很多问题需要解决:分离代码,分

小程故事多 | 看来微服务就是一把双刃剑

微服务是银弹吗?自2014年"微服务"一词真是越来越火,不谈Microservices彷佛就out了,那么我们先来看微服务具有哪些特点: 组件以服务的形式提供 围绕业务功能进行组织 强化终端与弱化管道 产品而不是项目 独立布署 单一职责 去中心化 DevOps与组织架构 我要讲的故事开始了 A公司的技术架构体系目前还是以集群扩展体系为主,我们可以看下图所示,在这种体系结构中,可以看到应用都是单块结构,但是单块结构的应用具有扩展性,通过布署在多个Tomcat上实现应用的集群,所有的应用都

微服务有奖话题:@coding哥,小猿媛叫你回家吃饭!

问题描述 那么,本期有奖话题活动规则如下:1.所有关于微服务的有效回复,每个ID将获得25c币2.参与2.3.4话题的有效回复,每个ID将获得52c币3.4个话题都参与并且有效的用户,将获得特百惠水杯.4.发表关于"微服务及相关技术独特见解"用户,将获得午睡神器.活动时间:2016年5月10日-6月10日话题1,coding哥,咱们智商这么高,平时只写代码是不是有点太浪费啦?话题2,小编妹子求各位开导,开发者真的是一个贬值最快的工作吗?您怎么看!最近小编妹子很烦恼,是因为她暗恋的那个c

微服务实践:全栈小团队“洪荒之力”改造阿里服务CRM技术体系

本文不重点介绍业务系统,更偏重于经验分享.首先进行了业务介绍,接着和大家简单分享了微服务,着重和大家讲述了微服务的实践,包括微服务技术实践.微服务团队实践.DT下的微服务. 以下为内容整理: 作为全球最大的电商平台,阿里巴巴面对的是逾4亿的活跃消费者.上千万的活跃商家.几千种阿里自有产品和业务,以及每天上千万笔的交易.从这些天然交易闭环里,有极其丰富的数据,如何用技术来实现用户的"One-Click"和"One-Stop"的服务体验? 通过微服务架构的应用,我们重构

SoundCloud:我们最终是如何使用微服务的?

本文讲的是SoundCloud:我们最终是如何使用微服务的,[编者的话]很多的技术文章着重介绍的都是项目后总结出的最佳实践,本文从另外的角度,介绍项目中解决问题的整个探索过程,详细讲述了在最终使用微服务架构之前所做的种种分析和尝试,这对于正在尝试解决问题的技术人员来说有很大的启示作用. 微服务是近期的热点. 当我在SoundCloud工作时,负责从一个巨大的Ruby on Rails应用程序里迁移到众多的微服务上.我已经多次讲述这个过程的技术问题了,在演讲里,也在SoundCloud的工程师博客