一个基于 Dubbo 的微服务改造实践

摘要: 微服务的理论已经够多,今天不妨看一个实战案例。

10-12 18:34 首页 InfoQ
策划|程超
编辑|小智
微服务的理论已经够多,今天不妨看一个实战案例。
写在前面

基于微服务或者 SOA 的自动化测试系统每个公司都有自己的特有的,我今天就主要介绍一下,我们研发的一套 mock 测试系统。

目前面临的问题
1、测试人员面临的测试问题

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

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

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

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

2、测试人员如何验证数据

接口返回值

通过肉眼分析比对接口返回值的内容,判断业务逻辑正确性。

数据库验证

测试接口的输入值需要通过手工编写数据库 SQL 查询获取,接口调用完成后,需要通过大量的 SQL 验证数据库值的正确性。

日志验证

通过返回值和数据库不能确保代码走到了预期的逻辑,只能通过肉眼观察日志确认代码的实际运行逻辑

测试报告

人工记录用例结果,人工编写报告,耗时耗力,难以准确定位代码问题

Mock 模拟系统的产生

业务系统调用众多其他系统完成功能逻辑,而想要得到其他系统接口的特定输出,需要做相应的运营配置,增加很多的沟通成本;甚至偶发性 bug 只能在特定的环境状况下复现,只能作为不可测的逻辑。

以风控系统为例,如果业务系统需要测试某个商编某个商品类别下的累积限额,需要风控的同事配合不断修改限额阈值,目前的情况是多个业务系统都在接入风控,配合测试的人力成本和时间成本是很高的。为此设计了挡板模拟系统,其功能结构如下:

针对测试人员测试用例数据无法沉淀和复用的问题,我们将采用“用例与日志锚点库”方案:

  • 用例库的建立可以实现对以往测试规则的记录与复用,改变每次回归测试都要重复编写用例与准备数据的现状。

  • 日志锚点库是对代码执行流程的有效验证,除了可以应用在测试环境中,还可基于大数据日志中心对生产代码的运行做日常监控。

  • 交易与支付系统业务逻辑复杂,靠人脑和文档记忆功能关系难免疏漏,而用例库和日志锚点库会随着业务的变更测试而随即维护,是一部活文档。

Mock 系统的技术方案
1、系统的功能点

说明: 上图罗列了整个 Mock 测试系统的功能点有哪些,共分为:配置接口数据、创建测试用例、创建测试集、创建测试计划、执行测试计划以及生成测试报告等大功能。

配置接口数据界面图

创建测试用例配置图

挡板请求路由配置图

测试执行结果

2、系统的功能流程图

说明:依据上下文环境,利用工厂类动态注入 spring 对远程接口的依赖,保持线上与测试的代码一致。在测试环境中,通过 mock 系统管理端,可以随时调整请求的流向,“指哪打哪”。

说明:执行某项测试用例, 利用 mock 将被测试接口与底层依赖接口隔离开来,可以方便的模拟数据,并监控输入输出。用例执行完毕后,使用返回断言、SQL 查询、日志标记等多种手段验证。

Dubbo 的 Mock 功能
1、Dubbo 的 Mock 使用

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

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

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

规则如下:

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

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


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

2、Dubbo Mock 的原理解析

在 dubbo 的配置文件中


可以看到如下配置列表:


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

  • AvailableCluster: 获取可用的调用。遍历所有 Invokers 判断 Invoker.isAvalible, 只要一个有为 true 直接调用返回,不管成不成功。

  • BroadcastCluster: 广播调用。遍历所有 Invokers, 逐个调用每个调用 catch 住异常不影响其他 invoker 调用。

  • FailbackCluster: 失败自动恢复, 对于 invoker 调用失败, 后台记录失败请求,任务定时重发, 通常用于通知。

  • FailfastCluster: 快速失败,只发起一次调用,失败立即保错,通常用于非幂等性操作。

  • FailoverCluster: 失败转移,当出现失败,重试其它服务器,通常用于读操作,但重试会带来更长延迟。

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


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

我们来看 MockClusterInvoker 的内部实现:

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


如果配置了强制执行 Mock,比如发生服务降级,那么直接按照配置执行 mock 之后返回。


如果是其它的情况,比如只是配置的是 mock=fail:return null,那么就是在正常的调用出现异常的时候按照配置执行 mock。


3、Dubbo Mock 的适用场景

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

自动化 Mock 系统的实现
1、Mock 系统的简单用例图

2、Mock 系统的架构图

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

Dubbo 的 Filter 原理分析

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

Filter 接口定义:


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


关于 SPI 的详细介绍请大家参考我之前写的另一篇文章:

http://www.jianshu.com/p/46aa69643c97

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


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


Mock 流程介绍

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

3、Mock 系统的配置中心

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

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

环境设置

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

应用名称设置

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

挡板规则

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

Facade 规则

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

方法规则

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

4、Mock 系统的其他功能

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

打个广告

科技发展日新月异,我们一直在为更高效快速的开发而努力,无论是一线开发者,还是技术管理者,抑或是产品经理,都在为此不断尝试。QCon 邀请到具有实战经验的架构师和技术专家带来最新前沿技术的探索进度,无论是架构还是前端,大数据或是软件性能,编程语言还有安全风控,各领域全涵盖,或许会对你有所启发。

QCon 上海站目前 9 折优惠报名中,2017 年 09 月 17 日前,立减 680 元,团购报名更多优惠~点击「 阅读原文 」跟技术大咖零距离。欲购票或咨询问题可联系购票经理 Hanna ,电话/微信:15110019061。


作者介绍

程超,InfoQ 签约作者,10 年 Java 工作经验,擅长和感兴趣的技术领域是分布式和大数据方面,目前主要从事金融支付类方向。

今日荐文

点击下方图片即可阅读

为什么 30 岁的工程师容易跳槽?




首页 - InfoQ 的更多文章: