Gatling 自动化压测&Jmeter

Gatling是一款基于Scala 开发的高性能服务器性能测试工具,它主要用于对服务器进行负载等测试;想使用Gatling进行压测的原因之一是想体验一下Scala编程的感觉,玩一下;第二,工作上也确实有这样的需求;

压测工作简单来说就是利用压测应用,来测试一下服务器的响应性能参数;然后把这些工作全部自动化,集成到jenkins中来运行。

整个工作的子任务分解可以由下图来表示:

Gatling 自动化压测&Jmeter_第1张图片
image

压测使用的是一个常见的web应用,该web应用的具体使用的业务场景如下:

Gatling 自动化压测&Jmeter_第2张图片
image

针对该应用的压测Scala源代码如下:
文件名:performance.scala

package performance

import scala.concurrent.duration._

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.jdbc.Predef._

class Performance extends Simulation {

  //用户名、餐馆ID 存储文件
  val user = csv("/root/.jenkins/workspace/testGatling/src/test/scala/data/user.csv").random
  val res = csv("/root/.jenkins/workspace/testGatling/src/test/scala/data/restaurant.csv").random
  val ip = csv("/root/.jenkins/workspace/testGatling/src/test/scala/data/ip.csv").random

  val httpProtocol = http
    .baseURL("http://${ip}:8180")

  val headers_0 = Map("Accept" -> "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")

  val scn = scenario("Emenu")
    //打开订餐首页
    .exec(http("index")
    .get("/E_Menu/userlogin/login.jsp")
    .headers(headers_0))

    //登录
    .pause(1 second,20 second)
    .feed(user)
    .feed(res)
    .exec(http("login")
    .post("/E_Menu/userlogin/login")
    .headers(headers_0)
    .formParam("username", "${username}")
    .formParam("password", "${password}")
    )

    //选择餐馆
    .pause(1 second,20 second)
    .exec(http("menu")
    .get("/E_Menu/menu.action?res_num=${rest_id}")
    .headers(headers_0)
    )
    //点菜
    .pause(1 second,20 second)
    .exec(addCookie(Cookie("username", "${username}")))
    .exec(addCookie(Cookie("res_num", "${rest_id}")))
    .exec(addCookie(Cookie("food_num0", "105")))
    .exec(addCookie(Cookie("food_num1", "104")))
    .exec(addCookie(Cookie("food_num2", "104")))
    .exec(addCookie(Cookie("food_num3", "106")))
    .exec(addCookie(Cookie("total", "52")))
    .exec(http("list") //点完菜,开始订
    .get("/E_Menu/list.action")
    .headers(headers_0)
    )
    //下单
    .pause(1 second,20 second)
    .exec(http("order")
    .get("/E_Menu/order.action?people=5&time=2025-08-31")
    .headers(headers_0)
    )

    //    //回首页
    .pause(1 second,20 second)
    .exec(http("restaurant")
    .get("/E_Menu/restaurant.action")
    .headers(headers_0)
    )

    //用户信息
    .pause(1 second,20 second)
    .exec(http("userinfo")
    .get("/E_Menu/userinfo?username=${username}")
    .headers(headers_0)
    )

    //我的订单
    .pause(1 second,20 second)
    .exec(http("userorder")
    .get("/E_Menu/userorder.action?username=${username}")
    .headers(headers_0)
    )

    //退出
    .pause(1 second,20 second)
    .exec(http("exit")
    .get("/E_Menu/userlogin/login.jsp")
    .headers(headers_0))

  setUp(scn.inject(atOnceUsers(100))).protocols(httpProtocol)
}

写完scala代码,并且保证它在本地可以调试通过,下一步就是需要将代码集成进jenkins;
先确保jenkins Gatling Plugin在jenkins上被安装;
之后,写入用来执行的shell调控代码:

#################### 环境准备 ####################
pwd
export IP="xx.xx.xx.xx"
export user="root"
export pwd="xxxxxxxxxx"
export tomcat_path="/root/apache-tomcat-7.0.56/bin"
export killtomcat="/root/killtomcat.sh"

#################### 定义函数 ####################
kill_tomcat7(){
expect -c "
spawn ssh $user@$IP sh $killtomcat;
expect {
yes/no { send yes\r;exp_continue }
*password: { send $pwd\r }
};
expect eof;
"
}

start_tomcat(){
expect -c "
spawn ssh $user@$IP sh $tomcat_path/$1;
expect {
yes/no { send yes\r;exp_continue }
*password: { send $pwd\r }
};
expect eof;
"
}
#################### tomcat压测 ####################

停止tomcat

kill_tomcat7

启动tomcat

start_tomcat startup_non.sh

mvn gatling:execute -Dgatling.simulationClass=performance.Performance

#################### 完毕 ####################

参考截图如下:

Gatling 自动化压测&Jmeter_第3张图片
image

在完成调试改bug工作之后,可以尝试运行一下,得到压测结果 Gatling report ,然后可以进行相关的数据分析,这里不再赘述。
Jenkins 集成 Gatling Report参考截图如下:

Gatling 自动化压测&Jmeter_第4张图片
image

11 个赞 关注 收藏

所以具体实现过程我这里不多写了,我重点写下对生成的HTML测试报告进行优化

如果按JMeter默认设置,生成报告如下:

Gatling 自动化压测&Jmeter_第5张图片
image

从上图可以看出,结果信息比较简单,对于运行成功的case,还可以将就用着。但对于跑失败的case,就只有一行assert错误信息。(信息量太少了,比较难找到失败原因)

优化大致过程

1、修改jmeter.properties文件,打开一些输出内容开关(下图根据需要选择相关项,具体就不用多说了吧)

Gatling 自动化压测&Jmeter_第6张图片
image

2、制定一份自己的输出模板。(不用默认的jmeter_home/extras/jmeter-results-detail-report.xsl模板,也可以网上自己找份。)
3、最后执行,生成对应的HTML报告(一般我们都在linux环境 下运行,语句大致如下,其中my_project_template.xsl就上第2步说的定制模板,这个是网上找的一份。)

xsltproc $jmeter_home/extras/my_project_template.xsl $my_project_workspace/result/jtl/$test_name/${test_name}.jtl > $my_project_workspace/result/html/$test_name/${test_name}.html

最后报告如下:

Gatling 自动化压测&Jmeter_第7张图片
image

Gatling 自动化压测&Jmeter_第8张图片
image

优化后的HTML报告,多了接口地址、接口参数、Headers信息(包括cookie、session),而且有返回结果。失败原因一目了然[图片上传失败...(image-9cb8f5-1527240193077)]

最后附上我的jmeter文件样本:

Gatling 自动化压测&Jmeter_第9张图片
image

什么是mock server

mock:英文可以翻译为模仿的,mock server是我们用来解除依赖(耦合),假装实现的技术,比如说,前端需要使用某些api进行调试,但是服务端并没有开发完成这些api,那么前端的工作就被服务端阻塞了,那么就可以使用mock server假装实现这些api,能够返回特定的数据,帮助前端进行页面渲染,当然我们为了方便可以需要与服务端进行约定,约定接口的内容是什么。

restful接口规范

转接阮一峰老师的博客—RESTful API 设计指南:http://www.ruanyifeng.com/blog/2014/05/restful_api.html

Moco-约定uri(一)

moco工具是在github开源的一个项目,可以使用moco工具搭一个简单的mock server方便我们进行调试,github地址:https://github.com/dreamhead/moco,下载下来的是一个jar包,目前的版本是0.11.1,首先我们要编写一个config文件,把我们需要“模拟”的请求和响应写入这个配置文件,配置文件是json格式的,接下来我们写一个比较简单的请求,访问 localhost:12306/hello 接口,返回一个纯文本“moco”,moco工具约定了12306端口,不必纠结,就跟tomcat约定8080端口类似,config.json文件如下,而且json文件要与moco的jar包放在同一个文件夹下。比如博主的目录结构:

G:\学习资料\mock\moco-runner-0.11.1-standalone.jar
G:\学习资料\mock\config.json

[
    {
        "request":
        {
            "uri":"/hello"
        },
        "response":
        {
            "text":"moco"
        }
    }
]

配置文件比较简单,我们请求接口,返回一个纯文本,启动指令:

>java -jar moco-runner-0.11.1-standalone.jar http -p 12306 -c config.json

这里的http就是http协议, -p 12306 绑定端口号12306, -c config.json读config文件

这里写图片描述

看到以上的表现,就说明moco已经顺利启动了,我们访问localhost:12306/hello 看到结果如下就说明mock server顺利返回了我们约定的数据”moco”


这里写图片描述

Moco-约定uri(二)

修改config文件如下,注意这里moco工具能实时监测到json配置文件的变化,并自行重启server


这里写图片描述
[
    {
        "request":
        {
            "uri":"/"
        },
        "response":
        {
            "text":"welcome to Moco"
        }
    },
    {
        "request":
        {
            "uri":"/hello"
        },
        "response":
        {
            "text":"moco"
        }
    }
]

接下来分别访问localhost:12306和12306:12306/hello,结果如下:


这里写图片描述
这里写图片描述

Moco-约定get请求

[
    {
        "request":
        {
            "method":"get",
            "uri":"/get"
        },
        "response":
        {
            "text":"moco get"
        }
    }
]

Moco-约定post请求

[
    {
        "request":
        {
            "method":"post",
            "uri":"/post"
        },
        "response":
        {
            "text":"moco post"
        }
    }
]

Moco-约定请求参数

[
    {
        "request":
        {
            "method":"get",
            "uri":"/get",
            "queries":
            {
                "id":"12306",
                "name":"moco"
            }
        },
        "response":
        {
            "text":"moco queries"
        }
    }
]
这里写图片描述

Moco-约定请求body必须为json格式

[
    {
        "request":
        {
            "method":"post",
            "uri":"/post",
            "text":
            {
                "json":"{\"id\":\"12306\",\"name\":\"moco\"}"
            }
        },
        "response":
        {
            "status":"200"
        }
    }
]

Moco-约定请求头部

[
    {
        "request":
        {
            "method":"post",
            "uri":"/post",
            "headers":
            {
                "content-type":"application/json",
                "Connection":"keep-alive",
                "Content-Encoding":"gzip"
            }
        },
        "response":
        {
            "status":"200"
        }
    }
]

Moco-约定返回内容

前面已经看到了response的集中返回内容如text,和status,下面展示一下返回文件和设置文件格式等

[
    {
        "request":
        {
            "method":"post",
            "uri":"/post",
        },
        "response":
        {
            "file":"data.js",
            "charset":"GBK",
            "version":"HTTP/1.0"
        }
    }
]

Moco-约定返回状态码

见上述的几个json,里面已经包含了返回状态码的使用方式

Moco-在单元测试中的使用(以Python为例)

[
    {
        "request":
        {
            "method":"get",
            "uri":"/api/hello"
        },
        "response":
        {
            "text":"hello Savitar!",
            "status":200
        }
    }
]

这里模拟一个get请求,返回纯文本“hello Savitar!”和状态码200,先在浏览器访问localhost:12306/api/hello 结果如下图:


这里写图片描述

说明接口返回没问题,接下来使用Python requests+unittest写一个简单的接口测试用例


#coding=utf-8
'''
@author=Savitar
'''
import unittest
import requests

class MocoTestApi(unittest.TestCase):
    def setUp(self):
        self.url = "http://localhost:12306"
    def test_moco_test_api(self):
        api = "/api/hello"
        url = self.url+api
        r = requests.get(url)
        self.assertEqual(r.status_code,200)
        self.assertEqual(r.text,"hello Savitar!")
    def tearDown(self):
        pass

if __name__ == '__main__':
    unittest.main()

你可能感兴趣的:(Gatling 自动化压测&Jmeter)