1 介绍
Gatling是一款基于Scala 开发的高性能服务器性能测试工具,它主要用于对服务器进行负载等测试,并分析和测量服务器的各种性能指标。Gatling主要用于测量基于HTTP的服务器,比如Web应用程序,RESTful服务等,除此之外它拥有以下特点:
Gatling适用的场景包括:测试需求经常改变,测试脚本需要经常维护;测试环境的客户机性能不强,但又希望发挥硬件的极限性能;能对测试脚本进行很好的版本管理,并通过CI进行持续的性能测试;希望测试结果轻量易读等。
2 与Jmeter对比:
图1和图2分别展现了二者在并发性能方面的表现。
图1,JMeter 2.8
图2,Gatling 1.3.2
3 使用、
3.1 下载:http://gatling.io/#/download,解压即可使用
3.2 文件目录介绍
当运行gating脚本的时候,其会扫描user-files目录下的所有文件,列出其中所有的Simulation(一个测试类,里面可以包含任意多个测试场景)。选择其中一个Simulation,然后填写Simulation ID和运行描述,这个都是为报告描述服务的。
3.3 录制-
3.3.1 启动录制:
3.3.2 界面:
3.3.3 录制配置
需要配置Internet的代理才能录制成功。录制完成之后代码保存在user-files/simulations/ 目录下
4 运行:
4.1 运行脚本
4.2 运行的时候会把所有的能运行的场景(simulation)都列出来,选择想要运行的即可。
5 测试结果
Gatling测试报表基于HTML,并且在测试过程中业已生成,所以打开速度很快。而且,当把鼠标移动到不同数据轴上时,都会有弹出框显示这个点上详细的测试数据信息。这种动态显示数据的方式非常方便查看和分析数据。考虑到项目真实数据的不便,我将通过Gatling官方网站给出的示例报表进行说明。
Gatling的报表分为两类:GLOBAL和DETAILS,其中GLOBAL主要是请求相关的统计数据,比如每秒请求数,请求成功与失败数等;其中DETAILS主要是请求时间相关的统计数据,比如请求响应时间,请求响应延迟时间等。
图4 每秒请求数,
当鼠标放到图中任何一个点的时候,对应时间点上请求的详细数据就会以图中白色的弹出框的方式进行显示。在下面的请求响应延迟时间图里面也有同样的功能。
图5 请求响应延迟时间,
6 进阶
脚本解析:
package computerdatabase // 1 包名
import io.gatling.core.Predef._ // 2必须导入的
import io.gatling.http.Predef._
import scala.concurrent.duration._
class BasicSimulation extends Simulation { // 3 类声明,必须继承Simulation
val httpConf = http // 4 所有Http请求普遍配置
.baseURL("http://computer-database.gatling.io") // 5 base URL
.acceptHeader("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") // 6 请求头
.doNotTrackHeader("1")
.acceptLanguageHeader("en-US,en;q=0.5")
.acceptEncodingHeader("gzip, deflate")
.userAgentHeader("Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0")
val scn = scenario("BasicSimulation") // 7 定义场景
.exec(http("request_1") // 8 http请求名称 request_1,这个名称最后会显示在报告中
.get("/")) // 9 get请求方法
.pause(5) // 10 暂停/思考时间 5s
setUp( // 11 建立场景
scn.inject(atOnceUsers(1)) // 12 声明注入一个用户
).protocols(httpConf) // 13 之前声明的Http请求配置
}
6.1 分离场景:分离操作:如浏览、搜索、编辑操作
object Search{valsearch=exec(http("Home")// let's give proper names, as they are displayed in the reports
.get("/")).pause(7).exec(http("Search").get("/computers?f=macbook")).pause(2).exec(http("Select").get("/computers/6")).pause(3)}objectBrowse{valbrowse=???}objectEdit{valedit=???}
We can now rewrite our scenario using these reusable business processes:
valscn=scenario("Scenario Name").exec(Search.search,Browse.browse,Edit.edit)
6.2 设置常规用户和管理员账户
val users=scenario("Users").exec(Search.search,Browse.browse)
val admins=scenario("Admins").exec(Search.search,Browse.browse,Edit.edit)
6.3 设置虚拟用户
setUp(users.inject(atOnceUsers(10)).protocols(httpConf))
6.4 设置上升压力,即每隔一段时间启动多少用户
setUp(users.inject(rampUsers(10)over(10seconds)),admins.inject(rampUsers(2)over(10seconds))).protocols(httpConf)
10s 内启动10个users和2个admin
6.5 参数化 or 动态数据
6.5.1 创建文件:在user-files/data文件夹下创建cvs文件,如:search.csv ,内容如下:
searchCriterion,searchComputerName
Macbook,MacBook Pro
eee,ASUS Eee PC 1005PE
6.5.2 使用文件:
objectSearch{
valfeeder=csv("search.csv").random// 1, 2
valsearch=exec(http("Home").get("/")).pause(1).feed(feeder)// 3
.exec(http("Search").get("/computers?f=${searchCriterion}")// 4
.check(css("a:contains('${searchComputerName}')","href").saveAs("computerURL")))// 5
.pause(1).exec(http("Select").get("${computerURL}"))// 6
.pause(1)}
6.5.3 解释:
Explanations:
6.6 循环调用
In the browse process we have a lot of repetition when iterating through the pages. We have four times the same request with a different query param value. Can we change this to not violate the DRY principle?
First we will extract the repeated exec block to a function. Indeed, Simulation‘s are plain Scala classes so we can use all the power of the language if needed:
objectBrowse{defgotoPage(page:Int)=exec(http("Page "+page).get("/computers?p="+page)).pause(1)valbrowse=exec(gotoPage(0),gotoPage(1),gotoPage(2),gotoPage(3),gotoPage(4))}
We can now call this function and pass the desired page number. But we still have repetition, it’s time to introduce another builtin structure:
objectBrowse{valbrowse=repeat(5,"n"){// 1exec(http("Page ${n}").get("/computers?p=${n}"))// 2.pause(1)}}
Explanations:
6.7 结果校验:()
importjava.util.concurrent.ThreadLocalRandom// 1
valedit=exec(http("Form").get("/computers/new")).pause(1).exec(http("Post").post("/computers").check(status.is(session=>200+ThreadLocalRandom.current.nextInt(2))))// 2
Explanations:
To handle this random failure we use the tryMax and exitHereIfFailed constructs as follow:
valtryMaxEdit=tryMax(2){// 1exec(edit)}.exitHereIfFailed// 2
Explanations:
7 其他
7.1 可以与CI集成
7.2 实时监控: 支持用户数和请求数的实时监控
7.3 服务器监控功能(System under test metrics)。 http://gatling.io/docs/2.1.7/realtime_monitoring/index.html
参考链接:
1)13年文章:新一代服务性能测试工具Gatling:http://www.infoq.com/cn/articles/new-generation-server-testing-tool-gatling/
2) 官网介绍:http://gatling.io
3) 官网文档地址:http://gatling.io/#/docs