一、背景
随着主流系统的服务化设计,特别是SOA架构和微服务架构的流行,接口已经成为各系统间通信的桥梁。所以,接口的性能压测也变得越来越重要。
SOA(Server OrientedArchitecture,面向服务架构)是目前通用的组件模型。它将软件系统的不同功能模块(被称为服务)通过接口的形式联系起来。这里的接口可以是具体的接口服务也可以是连接两个模块通信的中间件。一个大型项目通常是由多个系统开发组成的,每个系统都有专门的研发团队来负责,单个系统的功能被称作一个模块。而模块的功能是按后台的接口实现和UI呈现来划分。
微服务架构在某种程度上是面向服务的架构SOA继续发展的下一步。基本上,这种架构类型是开发软件,网络或移动应用程序作为独立服务套件(又称微服务)的一种特殊方式。这些服务的创建仅限于一个特定的业务功能,如用户管理、用户角色、电子商务车、搜索引擎、社交媒体登录等。此外,它们是完全独立的,也就是说它们可以写入不同的编程语言并使用不同的数据库。集中式服务管理几乎不存在,微服务使用轻量级HTTP、REST或Thrift API进行通信。
二、主要目标
- 获得单接口/单业务容量
- 发现应用程序的性能瓶颈
- 发现数据库的性能瓶颈
三、测试策略
1、概述
很多时候我们在设计接口性能压测脚本需要调用系统接口平台,如果接口平台没有提供可用的UI界面,那么就需要我们自己写代码结合压测工具连接接口平台,按照对应的协议调用接口。接口方法运行过程中需要调用很多依赖的方法。依赖方法不同的返回内容也是需要考虑的。但是依赖接口内容我们是不可控的。有时候是依赖模块不能正常运行,有时是依赖模块还未开发完,有时是我们是客观上无条件让依赖模块返回想要的异常值。这时候我们在压测的时候就需要Mock系统实现了,在Mock系统(挡板)定义好接口相关数据后,填入目标返回结果,就能模拟依赖接口返回想要的内容
结合开源的性能测试工具JMeter(本文只讲此工具),只需要把URL通过模拟HTTP并发请求就可以得到对应的执行结果,再根据返回结果判断接口执行是否正确。
所以相对来说时间成本比较低,一个场景转化成测试脚本也是比较简单的事情。接口发布上线后,参数很少发生变化。因为接口做为服务发布后会有多个调用方,如果参数发生变化将通知所有调用方做响应的修改,否则将出现调用方无法使用的情况。接口定义稳定不太容易发生变化,所以接口性能压测的后期维护工作也就不多。
2、主要类型
类型 | 具体内容 |
---|---|
效率(性能) | 并发数、响应时间 、TPS、错误率、资源占用 |
稳定性 | 单用户长时间下的反复操作、多用户长时间并发操作、异常值下的长时间反复操作、最大故障时长 |
压力 | 超规格负载下的规格内的处理 |
恢复性 | 负载正常后,系统是否正常恢复 |
3、常见接口
目前主流系统的接口大致可分为HTTP接口和自研RPC(Remote Procedure call,远程过程调用)接口,而HTTP接口可能更为普遍一些。
3.1、HTTP接口
一般压测WEB系统都会接触HTTP接口
常见有HTTP和HTTPS两种协议
- HTTP 超文本传输协议,默认80端口
- HTTPS 安全超文本传输协议,可以理解为http协议的安全版,默443端口
HTTP常见两种请求方法:GET和POST
与Server进行请求/响应时,两种最常被用到的两种方法
- GET 从指定的资源请求数据
- POST向指定的资源提交要被处理的数据
3.2、RPC接口
RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。
其实简单的说,就是象调用本地的类的方法样来调用服务器端的方法实现。
需要要对RMI(Remote Method Invoke,远程方法调用)中的stu(桩)和skeleton(骨架)的概念有一点了解。RMI的代理模式是通过代理对象将方法传递给实际对象的。Stub驻留客户端,承担着代理远程对象实现者的角色。skeleton类帮助远程对象与stub连接进行通信。
主要组成元素:
主要原理:
实体对象和业务接口由客户端和服务端公用。
接口实现是由服务端对定义好的业务接口进行功能实现,并将接口实例注册服务中提供给客户端调用。
目前我们接触到RPC接口主要有Hession、Dubbo、HTTP、Thrift、Hprose等
- Hession、Dubbo、Thrift、Hprose都是远程方法调用的一种实现,客户端需要保留stub来调用接口。这就是为什么我们性能压测的时候需要Jmeter引用jar包。
- Hession:是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能,远程方法调用的一种,采用二进制RPC协议(基于Http协议),适合发送二进制数据,不适合复杂对象类型的传输。
- Dubbo:阿里巴巴开源的一个高性能优秀的服务框架,一个远程方法调用的框架。Dubbo注册中心负责服务地址的注册和查找,相当于服务目录:Dubbo监控中心负责统计各服务调用次数、调用时间
- Thrift:facebook开源的一个可互操作和可伸缩服务的框架一个远程方法调用的框架,可扩展且跨语言的服务的开发。允许你定义一个简单的定义文件中的数据类型和服务接口(IDL)。之后生成服务器骨架和客户端调用代理
- Hprose:国人开发的一个远程方法调用的开源框架。它是一个先进的轻量级的跨语言跨平台面向对象的高性能远程动态通讯中间件。
- HTTP:常见于WEB应用,基于HTTP协议传输文本。当一个URL发送请求时,服务端doGet或者doPost方法会被调用,获取相应的参数。压测HTTP接口时,只需要通过定位URL接口并传参断言,相对比较简单。
下面针对几种接口简要说明:
Hession接口压测:
通过接口URL获取接口,如果复制接口定义及其自定义类,包名尽量跟开发包保持一致,不建议使用直接复制代码的方式,因为这样不便于维护,使用Maven在pom文件引入接口和Hessian依赖的jar包。通常借助HessianSpringFactoryBean获取,再结合Jmeter自定义JAVA类请求和Stub的方式接入测试工具进行压测
HessianProxy是hessian client处理客户端请求的核心类,采用proxy模式,代理客户端对远程接口的调用,hessian client的主程序的时序图如下:
Dubbo接口压测:
如果通过Dubbo注册中心获取服务接口,那么搭建测试环境的时候需要指定Dubbo注册中心的地址,扩展Jmeter也需要配置Dubbo注册中心地址以及对外提供服务的接口名称。直连的方式在Jmeter需要导入Dubbo框架相关的JAR包。现在有现成的Jemter dubbo插件,直接引入即可
节点说明:
- Provider:暴露服务的服务提供方
- Consumer:调用远程服务的服务消费方
- Registry:服务注册与发现的注册中心
- Monitor:统计服务调用次数和服务调用时间的监控中心
- Container:服务运行容器
Jemter Dubbo插件地址:https://github.com/dubbo/jmeter-plugins-dubbo
Jemter DubboSample截图
Thrift接口压测:
通过Stub驻留客户端调用用接口描述语言来写接口(IDL),生成服务器skeleton(骨架)类和客户端调用代理,skeleton类帮助远程对象与stub驻留客户端连接进行通信,客户端和服务器端是紧耦合在一起的,你不能单独修改任何一端的接口(不是说服务器端代码的实现),服务器和客户端传递的数据类型是严格匹配的
Hprose接口压测:
由服务端对定义好的业务接口进行功能实现,并将接口实例注册服务中提供给客户端调用。本地的函数和方法作为服务发布,而客户端通过可以根据自己的需要来定义调用接口,或者直接调用服务器端的函数或方法。再结合j脚本方式或者自定义java请求和Stub的方式接入测试工具进行压测。
HTTP接口压测:
相对来说最简单,通过Jmeter HTTP Request Sampel并发调用接口断言即可
总之,接口压测测试方法因框架不同其实现请求压测有所差异,但总的来说都是获取接口,并发请求,参数化数据,执行脚本,断言结果,监控数据这些步骤。
下面来做两个实践小例子
四、实践小例子
首先介绍下什么叫Mock?
此处引用淘宝网《接口测试白皮书》中的对mock的定义:
mock 是指使用各种技术手段模拟出各种需要的资源以供测试使用。
被mock的资源通常有以下特征:
被测目标依赖该资源
该资源可能因为各种原因不稳定、返回结果不断变化或者并不总是能够获取到
该资源跟被测目标本身质量无关
这些资源可能是一个外部或底层接口、一个系统、一组数据对象或者是一整套目标软件的工作环境等。通过mock避免对外部真实资源的依赖实现对被测目标的孤立测试,从而大大降低测试的难度,节约测试成本。
需要注意的是利用mock通过的测试与使用真实环境通过的测试毕竟还是有一定差别的。有些时候我们就是需要所测试的系统能够处理依赖所产生的各种情况,包括正常情况和异常情况,我们同样不能保证我们的mock 可以模拟到每种这样的情况。因此只在确实有必要的情况下才运用mock。
4.1、Moco
简单来说Moco就是类似一个mock的工具框架,下载就是一个JAR包
在Moco的github上面有这段话。
Integration, especially based on HTTP protocol, e.g. web service, REST etc, is wildly used in most of our development.
In the old days, we just deployed another WAR to an application server, e.g. Jetty or Tomcat etc. As we all know, it's so boring to develop a WAR and deploy it to any application server, even if we use an embeded server. And the WAR needs to be reassembled even if we just want to change a little bit.
翻译过来:
集成,特别是基于HTTP协议的集成,例如web服务、REST等,在我们的大多数开发中都被广泛使用。
在过去,我们只是将另一场WAR包部署到应用服务器上,例如Jetty或Tomcat等。众所周知,开发一个WAR包并将其部署到任何应用服务器上是非常枯燥的,即使我们使用的是嵌入式服务器。war包也需要被重新打包即使我们只是想稍微改变一下。
简单来说,Moco就是解决了开发前端时没有后端支持,开发接口时依赖没有到位的尴尬场景。当然Moco的灵活性,让其有越来越多的应用场景,比如我们在开发接口性能压测脚本的时候。
特点:
- 只需要简单的配置request、response等即可满足要求,支持http、https、socket。可以说是非常的灵活性。
- 支持在request 中设置 Headers , Cookies , StatusCode等。
- 对GET、POST、PUT、DELETE等请求方式均支持,很适合web开发。
- 无需环境配置,有java环境即可。
- 修改配置后,立刻生效。只需要维护接口,也就是契约即可。
- 对可能用到的数据格式都支持,如json、text、xml、file等。
- 还能与其他工具集成,如Junit、Maven、Gradle等。
foo.json配置示例:
[
{
"response" :
{
"text" : "Hello, Moco"
}
}
]
加载配置启动Moco HTTP Server
java -jar moco-runner-<version>-standalone.jar http -p 12306 -c foo.json
Github地址:https://github.com/dreamhead/moco
4.2、压测HTTP GET方法
此处示例均只设置一个线程
startupGet.json
配置文件:
[
{
"description":"这是一个带cookies和参数的get请求",
"request":{
"uri":"/7dget",
"method":"get",
"cookies":{
"login":"7dgroup"
},
"queries":{
"name":"zuozewei",
"sex":"man"
}
},
"response":{
"text":"success!"
}
}
]
加载配置启动Moco HTTP Server
Jmeter设置Cookies
name字段为一个cookie的名称。
value字段为一个cookie的值。
domain字段为可以访问此cookie的域名,本机为localhost
非顶级域名,如二级域名或者三级域名,设置的cookie的domain只能为顶级域名或者二级域名或者三级域名本身,不能设置其他二级域名的cookie,否则cookie无法生成。
Jmeter设置HTTP GET Request
注意,查询字符串(名称/值对)是在 GET 请求的 URL 中发送的:/7dget?name1=value1&name2=value2
Jmeter接受的Response结果
正确接受到服务端的返回信息
4.3、压测HTTP POST方法
startupPost.json
配置文件:
[
{
"description":"这是一个带headers和cookies以及Json参数的post请求",
"request":{
"uri":"/7dpost",
"method":"post",
"headers":{
"content-type":"application/json"
},
"cookies":{
"login":"7dgroup"
},
"json":{
"name":"zuozewei",
"sex":"man"
}
},
"response":{
"status":200,
"json":{
"name":"success",
"code":"1"
}
}
}
]
加载配置启动Moco HTTP Server
Jmeter设置headers
Jmeter设置Cookies
Jmeter设置HTTP POST Request
注意此次参数的格式是JOSN格式,是在消息主体中发送的。
Jmeter接受的Response结果
根据我们的配置,服务端返回的是一个Json格式的返回数据
至此,我们的两个小实践就结束了
本文源码: