java-route icon indicating copy to clipboard operation
java-route copied to clipboard

高性能分布式Mock平台的框架与设计

Open edagarli opened this issue 9 years ago • 0 comments

一、背景

当前, 几乎所有的手机应用都不会是单机运行在机器中,而是配合一个或者多个后台服务共同完成所有操作。举个例子,一个微博客户端,在用户进行看帖、发帖、顶踩等操作时,都会将请求发送给微博的后台服务器进行处理。这种交互方式就是典型的C/S架构,交互图大概是介样子的: 2016-05-05 20 50 04

然而实际应用场景中,并不会只有一个后台服务,而是多个服务分而治之。比如上面例子中的微博客户端,可能会与后台的帖子服务器、点赞服务器、图片服务器(不要在意命名这些细节)等多个服务器产生交互请求。于是,这个时候的交互图变成了: 2016-05-05 20 50 11

上面都还只是提到了内部服务,那如果再加上一些必要的外联系统呢(比如广告服务、新闻服务、内容推荐服务、搜索服务等第三方服务)?可以看到交互图有些丧心病狂了: 2016-05-05 20 50 25

对于客户端来说,无论是内部服务还是外联服务,都是一些独立的外部server,客户端无法干涉也不应该干涉。那么在客户端的开发或测试过程中,应该如何让这些server“配合”做测试和联调呢?最简单粗暴的方式就是直接连接外部系统。但是这种方式有很大的缺陷:我们无法控制这些外部系统,只能覆盖到最基本的场景。同时这种方式也受到了很大的限制,万一这些外部系统还未开发完成或者暂时无法提供服务,那我们的联调、测试工作将被block住。所以,最可靠的方式就是自己构造或者模拟一些这样的server,然后再随意控制server的响应以覆盖所有联调和测试场景。这便是mock平台的作用。

二、现有mock平台的局限和新解决方案

当前业界也存在许多优秀的mock平台或工具,比如GoogleMock, EasyMock, MockServer等,但是这些mock平台工具多少存在着一些局限性:

  1. 作为单元测试工具,只适用于单元测试而无法适用功能测试或者性能测试,且一般都是某种语言专用,比如GoogleMock就是一个C++的mock框架;
  2. 可以作为http mock平台使用,但没有提供API随意添加、修改mock数据设置;
  3. 开放了API,但mock节点只有一个,当两个相同业务同时使用时容易造成冲突(请求url相同,后面的配置会覆盖前者);
  4. 节点单一且数据没有缓存机制,性能表现差,无法支持大数据测试;
  5. 没有随机输出的功能,不适用于稳定性or性能测试;
  6. 其它局限,比如扩展性差等。 为了解决以上种种问题,我特此设计和实现了一个高性能分布式的Mock解决方案。废话不多说,来看具体的设计思路吧。

三、整体架构和设计思路 2016-05-05 20 50 33

名词解释

MCS:Mock Control Server,即Mock平台的管理主控点,专用于维护、管理Mock节点,提供API配置、管理Mock数据。 MSN:Mock Service Node,mock服务节点,顾名思义,就是实际接收mock请求和响应请求的mock节点。MSN与MCS之间也通过http请求进行交互和通信。

设计思路

  • MCS与MSN是一对多的关系(假设平台用户规模非常大,MCS会部署成多个web server并通过nginx负载均衡,但概念上来看可以认为只有一个MCS);
  • MSN定时发送心跳http请求到MCS,发送频率一般设置为10s内,用短连接模拟出来一个伪长连接;
  • 图中的人代表用户或者测试框架、代码框架,即平台同时支持web和API两种配置mock数据的方式;
  • 平台支持自助搭建MSN节点,只要在MSN中配置mcs_host指向MCS线上环境即可。这种自助搭建的MSN称为私人节点,只供私人专用(通过生成随机密钥鉴别身份);
  • 配置mock数据时既可以指定私人MSN节点,也可以不指定。指定了MSN,如果该MSN状态为空闲且鉴权成功,mock配置便即刻生效。未指定MSN,MCS会先为用户随机分配一个可用的公有节点,然后配置好mock数据后将节点信息和配置结果返回给用户。为了保证有足够的公用MSN,MCS会定时监控可用MSN节点数量,在数量低于阈值时触发报警,我们将在收到报警后第一时间处理;
  • 配置好mock数据后,修改应用的后台server url配置,将请求指向MSN,MSN收到请求后将返回配置好的mock数据;
  • 如果mock配置了数据缓存,MSN会缓存该数据到内存中,后续有请求命中了缓存,MSN将不再向MCS查询,而是直接返回,从而大大提高处理速度;
  • MCS数据存储使用mysql数据库,在MSN节点数量小于200,应用请求频率低于1个/s时不会有性能问题。高频和大量请求需要配置mock数据为缓存模式;
  • MCS和MSN都是一个java web server。MCS用apache tomcat部署,MSN则采用较为轻量级的jetty部署;
  • 当MSN超过一段时间未被访问,或者用户调用接口请求释放MSN时,MCS会清除相关的mock数据,MSN也会释放所有数据缓存;
  • 架构图中的剪头1.1, 1.2代表配置mock数据时的交互数据流。2.1 - 2.4代表一个完整mock请求的交互数据流。这两个流都在一个http请求中完成。详细情况如下:
    • 1.1 用户向MCS请求配置mock数据
    • 1.2 MCS配置好后将分配的MSN节点信息返回给用户
    • 2.1 应用发送请求给MSN
    • 2.2 MSN解析出请求路径和参数,向MCS查询该请求对应的mock响应
    • 2.3 MCS找到响应,返回给MSN
    • 2.4 MSN将响应转发给应用

四、缓存模式

本文所描述的mock平台设计初衷是完成一个高性能的分布式mock平台。分布式体现在MSN散步于不同机器,避免单一节点造成数据冲突和集中访问带来的性能瓶颈。但是从之前架构图和交互流程可以看出,MSN在处理mock请求时需要向MCS查询对应的响应数据,如果有一个应用持续高频地发送大量请求到MSN,也会造成MSN大量请求MCS,再加上众多MSN的心跳请求,MCS势必会成为整个方案的瓶颈所在。为了解决这个问题,让mock平台成为一个支持性能测试的真正意义上的高性能分布式mock平台,我们引入了mock数据缓存模式的概念。 缓存模式的实现比较简单:在配置mock数据的时候,增加缓存标识,如果用户设置缓存模式开启,则MSN在第一次查询到该mock数据时便将数据缓存到MSN内存中(需要控制缓存数据的数量和大小,避免将机器内存打满)。也就是说,MSN在处理mock请求的时候,实际上是先查找本地缓存,没有找到才会去查询MCS。因此,如果需要进行性能测试,只需将数据配置成缓存模式即可。这样不但省去了MSN请求MCS这一个步骤,还将读取MCS数据库变成了读取内存,性能和响应速度直接提升几个数量级。 缓存数据的清除就更加简单了。首先,MSN提供接口触发缓存数据的清除。其次,当释放、重新分配MSN时会进行环境的初始化,这时候不仅会清除MSN中的缓存,还会清除MCS中给该MSN配置的mock数据。

五、二期扩展功能

一期实现暂时只是一个比较简单的mock平台,不过已经五脏俱全,可以满足基本的mock需求了。 二期规划主要增加3个功能点:随机响应、其它协议支持以及代理录制。

随机响应

随机响应指通过某种约定方式配置mock数据,让MSN收到请求时可以随机生成响应返回给应用。举个例子,假设应用请求的真实返回是json格式的:

{ "retCode": 0, "retMsgs": "success", "retData": 100 }

可见retData是一个整数,如果正常情况下接口返回的retData范围是1 ~ 65535,那么就可以设置retData为一个1 ~ 65535之间的正整数,MSN在收到请求时便可以为retData选取一个1 ~ 65535之间的随机数,这样便完成了一个随机响应。其它数据类型如float、double、string等亦类似,不再赘叙。 随机响应功能的适用场景有:稳定性测试、健壮性测试和性能测试。

其它协议支持

有些时候,应用与后台服务的交互并不是采用http协议,而是采用其它一些协议如tcp socket, soap, rpc, thrift等。又或者不仅仅使用http而是采用更加安全的https协议。 为了提升mock平台的通用性,二期增加多种协议支持,为产品线定制开发其它各种协议的MSN节点。

代理录制

从上面的架构和详细设计中可以看出,用户在配置好mock后还需要修改应用的配置才能将请求指向MSN。如果应用是一个web server或者二进制程序,一般情况下只需要修改配置后重启即可。但如果应用是一个手机app,还要修改配置后重新编译打包、安装部署,整个过程较为耗时。为了减少这些麻烦,二期规划将MSN改造成代理服务器,用户只需要为手机配置好代理网络指向MSN即可使用mock服务,无需修改任何应用配置。这就相当于MSN截获了应用的所有网络请求,通过解析请求协议类型和请求url、路径和参数,向MCS查询到相应的mock结果后返回给应用,这个过程对应用来说是完全透明的。 既然能够截获所有请求,MSN还可以做的一件事就是开启完全代理模式,将请求转发给实际后台server,并记录所有请求、响应数据。用户后续可以一键将这些请求响应数据转化为mock数据配置,这些配置代表了真实返回,可以用作性能测试和场景测试,当数据量大的时候,可以省去很多数据构造工作。

edagarli avatar May 05 '16 12:05 edagarli