您的位置:首页 > 其它

Gatling 压力测试实例:多个虚拟用户回放多个请求

2016-01-15 21:21 731 查看
Gatling 是一款基于Scala 开发的高性能服务器性能测试工具,它主要用于对服务器进行负载等测试,并分析和测量服务器的各种性能指标。Gatling主要用于测量基于HTTP的服务器,比如Web应用程序,RESTful服务等...

压力测试需求:
跑步App主要功能:马拉松比赛时,多人使用跑步软件上传轨迹数据,另有多人下载跑步者的轨迹数据,达到实时观看马拉松跑步轨迹的目的。

现在要测量跑步App的服务器能承受的最大并发用户量。

压力测试的步骤1:创建虚拟用户

浏览器中打开网页: http://12.34.56.78/marathon/useradmin/create_chunk_users.php?phonestart=1231231000&usercount=10&prefix=uc

说明:

12.34.56.78 —— 服务器ip

12312310000 —— 将生成帐号的起始手机号

usercount=10 —— 生成10组帐号,每组帐号包含1个跑步者,4个观看者

prefix —— 帐号名前缀

php脚本生成的网页内容:

runnerName,runnerPassword,runnerNickname,watcher1Name,watcher1Password,watcher1Nickname,watcher2Name,watcher2Password,watcher2Nickname,watcher3Name,watcher3Password,watcher3Nickname,watcher4Name,watcher4Password,watcher4Nickname
1231231000,123456,ucr0,1231231001,123456,ucr0w1,1231231002,123456,ucr0w2,1231231003,123456,ucr0w3,1231231004,123456,ucr0w4
1231231005,123456,ucr1,1231231006,123456,ucr1w1,1231231007,123456,ucr1w2,1231231008,123456,ucr1w3,1231231009,123456,ucr1w4
1231231010,123456,ucr2,1231231011,123456,ucr2w1,1231231012,123456,ucr2w2,1231231013,123456,ucr2w3,1231231014,123456,ucr2w4
1231231015,123456,ucr3,1231231016,123456,ucr3w1,1231231017,123456,ucr3w2,1231231018,123456,ucr3w3,1231231019,123456,ucr3w4
1231231020,123456,ucr4,1231231021,123456,ucr4w1,1231231022,123456,ucr4w2,1231231023,123456,ucr4w3,1231231024,123456,ucr4w4
1231231025,123456,ucr5,1231231026,123456,ucr5w1,1231231027,123456,ucr5w2,1231231028,123456,ucr5w3,1231231029,123456,ucr5w4
1231231030,123456,ucr6,1231231031,123456,ucr6w1,1231231032,123456,ucr6w2,1231231033,123456,ucr6w3,1231231034,123456,ucr6w4
1231231035,123456,ucr7,1231231036,123456,ucr7w1,1231231037,123456,ucr7w2,1231231038,123456,ucr7w3,1231231039,123456,ucr7w4
1231231040,123456,ucr8,1231231041,123456,ucr8w1,1231231042,123456,ucr8w2,1231231043,123456,ucr8w3,1231231044,123456,ucr8w4
1231231045,123456,ucr9,1231231046,123456,ucr9w1,1231231047,123456,ucr9w2,1231231048,123456,ucr9w3,1231231049,123456

内容是excel格式的每组帐号的手机号、密码、昵称

此网页内容保存到压力测试服务器的 ~/gatling-charts-highcharts-bundle-2.1.7/user-files/data/runner-watcher-10.csv 中

压力测试的步骤2:生成跑步轨迹数据文件

浏览器中打开网页:

http://12.34.56.78/marathon/dump/locations.php?starttime=2015-12-22%2015:38:54&userid=12345
可以导出帐号12345的已结束跑步的轨迹数据,示例如下:

toff1,lat1,lng1,toff2,lat2,lng2,toff3,lat3,lng3,toff4,lat4,lng4,toff5,lat5,lng5
2,31.328442,120.432391,4,31.328441034483,120.43249606897,6,31.328440068966,120.43260113793,8,31.328439103448,120.4327062069,10,31.328438137931,120.43281127586,
12,31.328437172414,120.43291634483,14,31.328436206897,120.43302141379,16,31.328435241379,120.43312648276,18,31.328434275862,120.43323155172,20,31.328433310345,120.43333662069,
22,31.328432344828,120.43344168966,24,31.32843137931,120.43354675862,26,31.328430413793,120.43365182759,28,31.328429448276,120.43375689655,30,31.328428482759,120.43386196552,
32,31.328427517241,120.43396703448,34,31.328426551724,120.43407210345,36,31.328425586207,120.43417717241,38,31.32842462069,120.43428224138,40,31.328423655172,120.43438731034,
42,31.328422689655,120.43449237931,44,31.328421724138,120.43459744828,46,31.328420758621,120.43470251724,48,31.328419793103,120.43480758621,50,31.328418827586,120.43491265517,
52,31.328417862069,120.43501772414,54,31.328416896552,120.4351227931,56,31.328415931034,120.43522786207,58,31.328414965517,120.43533293103,60,31.328414,120.435438,
62,31.328413228571,120.435541,64,31.328412457143,120.435644,66,31.328411685714,120.435747,68,31.328410914286,120.43585,70,31.328410142857,120.435953,
72,31.328409371429,120.436056,74,31.3284086,120.436159,76,31.328407828571,120.436262,78,31.328407057143,120.436365,80,31.328406285714,120.436468,
82,31.328405514286,120.436571,84,31.328404742857,120.436674,86,31.328403971429,120.436777,88,31.3284032,120.43688,90,31.328402428571,120.436983,
92,31.328401657143,120.437086,94,31.328400885714,120.437189,96,31.328400114286,120.437292,98,31.328399342857,120.437395,100,31.328398571429,120.437498,

内容为excel格式的轨迹数据,每行数据为每10秒上传的5个点。

此网页内容保存到压力测试服务器的~/gatling-charts-highcharts-bundle-2.1.7/user-files/data/location-taihu-42km.csv 中

截取location-taihu-42km.csv 的229行,可以另存为location-taihu-10km.csv。

压力测试的步骤3:运行

压力测试服务器上,输入
~/gatling-charts-highcharts-bundle-2.1.7/bin$ ./gatling.sh

输入0选择第一个测试用例Marathon.RunningSimulation,再按两次回车,就开始压力测试了

shen@debian:~/gatling-charts-highcharts-bundle-2.1.7/bin$ ./gatling.sh
GATLING_HOME is set to /home/shen/gatling-charts-highcharts-bundle-2.1.7
Choose a simulation number:
[0] Marathon.RunningSimulation
[1] computerdatabase.BasicSimulation
[2] computerdatabase.advanced.AdvancedSimulationStep01
[3] computerdatabase.advanced.AdvancedSimulationStep02
[4] computerdatabase.advanced.AdvancedSimulationStep03
[5] computerdatabase.advanced.AdvancedSimulationStep04
[6] computerdatabase.advanced.AdvancedSimulationStep05
0
Select simulation id (default is 'runningsimulation'). Accepted characters are a-z, A-Z, 0-9, - and _

Select run description (optional)

运行过程中的输出:

================================================================================
2015-12-23 13:51:38                                         170s elapsed
---- running -------------------------------------------------------------------
[--------------------------------------------------------------------------]  0%
waiting: 0      / active: 1      / done:0
---- Requests ------------------------------------------------------------------
> Global                                                   (OK=198    KO=0     )
> login                                                    (OK=5      KO=0     )
> start_workout                                            (OK=1      KO=0     )
> start_session                                            (OK=1      KO=0     )
> upload_location                                          (OK=15     KO=0     )
> get_last_location                                        (OK=176    KO=0     )
================================================================================

Gatling压力测试脚本摘要

RunningSimulation.scala

package Marathon

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import scala.concurrent.duration._
import java.text.SimpleDateFormat
import java.util.Date

class RunningSimulation extends Simulation {

val httpConf = http
.baseURL("http://12.34.56.78/marathon/api")

val userFeeder = csv("runner-watcher-10.csv").circular

object RunAndWatch {

val records = csv("location-taihu-10km.csv").records

val runAndWatch = foreach(records, "record") {
exec(flattenMapIntoAttributes("${record}"))
.exec(
http("upload_location")
.post("/Workout/saveWorkoutSegment")
.headers(headers_urlencoded)
.formParam("userid", "${runner_uid}")
.formParam("sessionid", "abcd")
.formParam("workout", """{
"contenttype": "sessiondata",
"users_id": "${runner_uid}",
"starttime": "${w_starttime}",
"lap": [
{
"starttime": "${s_starttime}",
"locationdata": [
{
"timeoffset": "${toff1}",
"latitude": "${lat1}",
"longitude": "${lng1}",
},
{
"timeoffset": "${toff2}",
"latitude": "${lat2}",
"longitude": "${lng2}",
},
{
"timeoffset": "${toff3}",
"latitude": "${lat3}",
"longitude": "${lng3}",
},
{
"timeoffset": "${toff4}",
"latitude": "${lat4}",
"longitude": "${lng4}",
},
{
"timeoffset": "${toff5}",
"latitude": "${lat5}",
"longitude": "${lng5}",
}
]
}
]
}""")
)
.pause(3)
.exec(
http("get_all_location")
.post("/Workout/getLatestData")
.headers(headers_urlencoded)
.formParam("userid", "${watcher1_uid}")
.formParam("sessionid", "abcd")
.formParam("id", "${runner_uid}")
.formParam("startsplit", "0")
//.check(bodyString.saveAs("watcher1_location_body"))
)
.exec{ session =>
val df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
val now = df.format(new Date())
session.set("watcher1_lasttime", now)
}
.pause(3)
.exec(
http("get_all_location")
.post("/Workout/getLatestData")
.headers(headers_urlencoded)
.formParam("userid", "${watcher1_uid}")
.formParam("sessionid", "abcd")
.formParam("id", "${runner_uid}")
.formParam("startsplit", "0")
//.check(bodyString.saveAs("watcher1_location_body"))
)
.exec{ session =>
val df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
val now = df.format(new Date())
session.set("watcher1_lasttime", now)
}
.pause(3)
.exec(
http("get_all_location")
.post("/Workout/getLatestData")
.headers(headers_urlencoded)
.formParam("userid", "${watcher1_uid}")
.formParam("sessionid", "abcd")
.formParam("id", "${runner_uid}")
.formParam("startsplit", "0")
//.check(bodyString.saveAs("watcher1_location_body"))
)
.exec{ session =>
val df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
val now = df.format(new Date())
session.set("watcher1_lasttime", now)
}
.pause(1)
}
}

val headers_urlencoded = Map("Content-Type" -> "application/x-www-form-urlencoded")

val scn = scenario("running")
.feed(userFeeder)
.exec{ session =>
//println(session)
session
}
.exec(
http("login")
.post("/User/login")
.headers(headers_urlencoded)
.formParam("name", "${runnerName}")
.formParam("password", "${runnerPassword}")
.check(jsonPath("$.result.id").saveAs("runner_uid"))
)
.pause(1)
.exec(
http("login")
.post("/User/login")
.headers(headers_urlencoded)
.formParam("name", "${watcher1Name}")
.formParam("password", "${watcher1Password}")
.check(jsonPath("$.result.id").saveAs("watcher1_uid"))
)
.pause(60)
.exec{ session =>
//println(session)
val df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
val now = df.format(new Date())
session.set("w_starttime", now)
}
.exec(
http("start_workout")
.post("/Workout/saveWorkoutSegment")
.headers(headers_urlencoded)
.formParam("userid", "${runner_uid}")
.formParam("sessionid", "abcd")
.formParam("workout", """{
"contenttype": "workouthead",
"users_id": "${runner_uid}",
"starttime": "${w_starttime}",
"type": "1"
}""")
.check(bodyString.saveAs("start_workout_body"))
.check(jsonPath("$.result.id").saveAs("workout_id"))
)
.pause(1)
)
.exec{ session =>
val df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
val now = df.format(new Date())
session.set("watcher1_lasttime", now)
}
.exec(RunAndWatch.runAndWatch)
.exec{ session =>
//println(session)
session
}
)
.pause(1)
.exec(
http("end_workout")
.post("/Workout/saveWorkoutSegment")
.headers(headers_urlencoded)
.formParam("userid", "${runner_uid}")
.formParam("sessionid", "abcd")
.formParam("workout", """{
"contenttype": "workoutend",
"users_id": "${runner_uid}",
"starttime": "${w_starttime}",
}""")
)

setUp(scn.inject(rampUsers(10) over(60 seconds)).protocols(httpConf))
//setUp(scn.inject(atOnceUsers(1)).protocols(httpConf))
}

10个跑步者和10个观看者在60秒内登录完成,然后开始跑步和观看。1人跑,1人看,共10组用户。

测试报告:

800组用户到达性能瓶颈



最主要指标:
95th percentile 1436


表示95% upload_location请求的响应时间低于1436毫秒,上图是800组用户的情况,已经到达性能瓶颈。

如果总共100个请求,那么从快到慢的第95个请求的响应时间为1436毫秒。

700组用户请求响应迅速



95% upload_location请求的响应时间低于364毫秒

压力测试结论:
目前的服务器能承受700组并发用户,一组用户是指1个跑步者+一个观看者。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Gatling 压力测试