一篇入門 — Gatling 性能測試手冊

介紹

本篇博客,旨在記錄學習的要點,因此格式隨意, 方便本人往後自考和回憶,有興趣的朋友能夠評論討論。
原文地址:https://www.cnblogs.com/clockq/p/10539974.htmljavascript

一. 性能測試基礎

1.1 性能測試時什麼?

==性能測試時經過自動化的測試工具模擬多種正常峯值、以及異常負載條件,以此來對系統的各項性能指標進行評測。==css

性能測試 = 負載測試 + 壓力測試html

  1. 經過負載測試,肯定在各類工做負載下系統的性能,目的是測試系統的負載逐漸增長的狀況下,系統的各項性能指標的變化狀況。
  2. 經過壓力測試,肯定一個系統的瓶頸或者不能接受的性能點,來得到系統所能提供的最大服務級別。

1.2 ==性能測試的目的==

  1. 評估系統的能力
  2. 識別體系中的弱點
  3. 系統調優
  4. 檢查軟件中的問題
  5. 驗證系統穩定性
  6. 驗證系統可靠性

1.3 性能測試的常見觀察指標

  • Avg Rps: 平均每秒響應次數 = 總請求時間 / 秒數
  • Avg time to last byte per terstion(mstes): 平均每秒業務腳本迭代次數
  • Successful Rounds: 成功的請求
  • Failed Hits: 失敗的單擊次數
  • Hits Per Second: 每秒單擊次數
  • Successful Hits Per Second: 每秒成功的單擊次數
  • Failed Hist Per Second: 每秒失敗的單擊次數
  • Attempted Connections: 嘗試鏈接數
  • Throughput: 吞吐率

同時,對於服務端的CPU佔有率,內存佔有率,數據庫鏈接池等也是須要觀察的重點。前端

1.4 性能測試的基本流程

  1. 明確性能測試需求
  2. 制定性能測試方案
  3. 編寫性能測試案例
  4. 執行性能測試案例
  5. 分析性能測試結果
  6. 生成性能測試報告

二. Gatling基礎 -> 基礎使用法

2.1 安裝Gatling

獲取安裝包 http://gatling.io.download/
下載成功後解壓便可 使用Gatling須要安裝JDKjava

2.2 使用Gatling

  1. 編寫測試腳本(這塊重點學習和講解)或者使用自帶的錄製器(bin/recorder.sh)
  2. 執行測試腳本(bin/gatling.sh),在開啓的窗口中選擇要執行的腳本
  3. 查看測試報告(報告默認在「result/」目錄下)
  4. 分析測試結果

三. Gatling 和 Mvn 整合使用 (推薦)

3.1 導入依賴

<properties>
        <gatling.version>2.1.7</gatling.version>
        <gatling-plugin.version>2.1.7</gatling-plugin.version>
    </properties>
    
    <!-- Gatling Module -->
    <dependency>
        <groupId>io.gatling.highcharts</groupId>
        <artifactId>gatling-charts-highcharts</artifactId>
        <version>${gatling.version}</version>
    </dependency>

3.2 導入插件

<build>
    <sourceDirectory>src/test/scala</sourceDirectory>
    <testSourceDirectory>src/test/scala</testSourceDirectory>
    <plugins>
        <!-- Gatling Maven plugin that runs the load-simulation. -->
        <plugin>
            <groupId>io.gatling</groupId>
            <artifactId>gatling-maven-plugin</artifactId>
            <version>${gatling-plugin.version}</version>
            <configuration>
                <configFolder>src/test/resources</configFolder>
                <dataFolder>src/test/resources/data</dataFolder>
                <resultsFolder>target/gatling/results</resultsFolder>
                <runMultipleSimulations>true</runMultipleSimulations>
                <simulationsFolder>src/test/scala/com/pharbers/gatling</simulationsFolder>

                <simulationClass>com.pharbers.gatling.scenario.getHome</simulationClass>

                <!--    <noReports>false</noReports> -->
                <!--   <reportsOnly>directoryName</reportsOnly> -->
                <!--   <simulationClass>foo.Bar</simulationClass> -->
                <!--   <jvmArgs> -->
                <!--     <jvmArg>-DmyExtraParam=foo</jvmArg> -->
                <!--   </jvmArgs> -->
                <!--    <fork>true</fork> -->
                <!--    <propagateSystemProperties>true</propagateSystemProperties> -->
                <!--   <failOnError>true</failOnError> -->
            </configuration>
        </plugin>
    </plugins>
</build>

3.3 編寫腳本

忽略
注意: 腳本要寫在 src/test/scala 下web

3.4 執行腳本

mvn gatling:execute數據庫

3.5 分析報告

四. 現實測試舉例

咱們先以測試「博客園系統登陸頁」性能爲例,講解一次測試過程的幾個步驟,和測試報告怎麼分析。json

4.1 明確性能測試需求

好的開始是成功的一半api

明確性能測試的需求是相當重要的,因此咱們要先有一份測試需求實例服務器

測試需求名稱: 博客園登陸接口性能測試 | 信息描述 | 描述內容 | | :--: | :--: | | 參與者 | 張三 | | 概述 | 測試博客園登陸接口的最大併發量 | | 前置條件 | 博客園前端頁面已經成功部署,並能夠正常訪問 | | 後置條件 | 無 | | 業務數據 | 測試登陸帳號 | | 不可測試緣由 | 網絡不可達 | | 流程規則 | 用戶訪問博客園登陸頁,滯留5s,以後調用登陸接口 | | 業務規則 | 無 | | 頁面規則 | 無 | | 特殊規則 | 無 | | 接口規則 | 無 | | 檢查內容 | 檢查當用戶量達到多大時,會致使服務端阻塞,用戶響應時間超過5s |

4.2 編寫性能測試案例

測試需求名稱: 博客園登陸接口性能測試 | 測試步驟 | 步驟描述 | 預期結果 | | :--: | :--: | :--: | | 步驟 1 | 是否測試博客園登陸接口最大併發量 | 肯定性能測試登陸接口的併發用戶數量 | | 步驟 2 | 啓動博客園的前端工程 | 前端工程啓動成功 | | 步驟 3 | 準備性能測試腳本 | 性能測試腳本準備完成 | | 步驟 4 | 準備測試數據 | 無 | | 步驟 5 | 執行腳本,驗證系統是否知足相關性能測試指標 平均響應時長<2s 95%響應時長<= 5s | 系統知足相關性能測試指標 | | 步驟 5 | 執行1小時壓力測試 | 1. 系統知足相關性能測試指標 2. 1小時壓力測試中腳本未報錯 |

4.3 執行性能測試案例

按照性能測試案例編寫測試腳本

package com.pharbers.gatling.base

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.http.config.HttpProtocolBuilder

object phHttpProtocol {
    implicit val noneWhiteList: io.gatling.core.filter.WhiteList = WhiteList()
    implicit val noneBlackList: io.gatling.core.filter.BlackList = BlackList()
    implicit val staticBlackList: io.gatling.core.filter.BlackList = BlackList(""".*\.js""", """.*\.css""", """.*\.gif""", """.*\.jpeg""", """.*\.jpg""", """.*\.ico""", """.*\.woff""", """.*\.(t|o)tf""", """.*\.png""")
    implicit val staticWhiteList: io.gatling.core.filter.WhiteList = WhiteList(""".*\.js""", """.*\.css""", """.*\.gif""", """.*\.jpeg""", """.*\.jpg""", """.*\.ico""", """.*\.woff""", """.*\.(t|o)tf""", """.*\.png""")

    def apply(host: String)
             (implicit blackLst: io.gatling.core.filter.BlackList, whiteLst: io.gatling.core.filter.WhiteList): HttpProtocolBuilder = { http
                .baseURL(host)
                .inferHtmlResources(blackLst, whiteLst)
                .acceptHeader("application/json, text/javascript, */*; q=0.01")
                .acceptEncodingHeader("gzip, deflate")
                .acceptLanguageHeader("zh-CN,zh;q=0.9,zh-TW;q=0.8")
                .doNotTrackHeader("1")
                .userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36")
    }
}
package com.pharbers.gatling.base

object phHeaders {

    val headers_base = Map(
        "Accept" -> "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "Upgrade-Insecure-Requests" -> "1")
}
package com.pharbers.gatling.scenario

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.core.structure.ChainBuilder

import com.pharbers.gatling.base.phHeaders.headers_base

object getHome {
	val getHome: ChainBuilder = exec(http("home")
			.get("/")
			.headers(headers_base))
}
package com.pharbers.gatling.scenario

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.core.structure.ChainBuilder

import com.pharbers.gatling.base.phHeaders.headers_json

object userLogin {
	val feeder = csv("loginUser.csv").random
	println(feeder)

	val login: ChainBuilder = exec(http("login")
			.get("/api/user/login")
			.headers(headers_json)
			.body(StringBody("""{ "condition" :  { "email" : "nhwa", "password" : "nhwa" } }""")).asJSON)
}
package com.pharbers.gatling.simulation

import io.gatling.core.Predef._
import scala.concurrent.duration._

import com.pharbers.gatling.scenario._
import com.pharbers.gatling.base.phHttpProtocol

class userLogin extends Simulation {
	import com.pharbers.gatling.base.phHttpProtocol.{noneBlackList, noneWhiteList}

	val httpProtocol = phHttpProtocol("http://192.168.100.141:9000")

	val scn = scenario("user_login")
		.exec(
			getHome.getHome
					.pause(5 seconds),
			userLogin.login
					.pause(60 seconds)
		)

	setUp(scn.inject(rampUsers(1000) over (3 seconds))).protocols(httpProtocol)

}

並執行上述腳本

4.4 分析性能測試結果

看下圖,能夠看到67% + 8%的請求能夠在1.2s內徹底,同時在1000用戶的併發測試下,會有用戶請求不到資源,也就是加載失敗。

其實,這個地方,能夠經過修改gatling.conf來改變表格的渲染區間,使結果更符合咱們的測試要求

image

這裏,75th的總響應時間=1s,仍是很快的,但95th的總響應時間>9s, 因此不符合咱們的測試要求。 image

咱們使用遞增的方式,在3s內逐漸增長用戶併發量,而且用戶會滯留5s + 60s,在下圖中就獲得了體現 image

下圖是本次測試,在每一個時間點的請求狀況,包含請求狀態(成功,失敗)和請求數量 image

還有更多圖表,就不一一展現了,咱們主要就是查看前兩個圖表,以此判斷服務器所能承受的壓力。

固然,若是須要考查更多標準,就須要查看其它圖表,好比延遲分佈圖,負載分佈圖等等。。。。

4.5 生成性能測試報告

一份合格的性能測試報告,至少應該包含以下內容:

  1. 測試基本信息: 包含: 測試目的,報告目標讀者,術語定義,參考資料
  2. 測試環境描述: 包含: 服務器軟硬件環境,網絡環境,測試工具,測試人員
  3. 性能測試案例執行分析: 須要詳細描述每一個測試案例的執行狀況,以及對對應測試結果進行分析
  4. 測試結果綜合分析及建議:對本次性能測試作綜合分析,並給出測試結論和改進建議
  5. 測試經驗總結

博客園登陸接口性能測試報告

測試信息

信息描述 描述內容
測試人員 齊鍾昱
測試目的 檢查當用戶量達到多大時,會致使服務端阻塞,用戶響應時間超過5s
術語定義 50th,安裝遞增排序後,排在50%的請求的信息
術語定義 95th,安裝遞增排序後,排在95%的請求的信息
參考資料 零成本實現Web性能測試[電子工業出版社]

測試環境

信息描述 描述內容
服務器系統 CentOS Linux release 7.4.1708 (Core)
服務器集羣數量 4
服務器內存(臺) 16G
服務器CPU核心數(臺) 12
服務器硬盤空間(臺) 256G SSD
JAVA版本 1.8.121
Scala版本 2.11.8
Play版本 2.5.0-M2
Redis版本 4.0.1
MongoDB版本 3.4.4
Node.js 8.11.2
Ember.js 2.18.2
網絡環境 公司局域網
測試工具 Gatling 2.1.7

結果分析

測試內容 預期結果 測試結果 備註
博客園系統登陸頁的最大訪問量 在當前環境下能夠1000用戶併發,不會形成用戶請求失敗 在3s內逐漸提升併發量,當併發量在643時有三個資源請求失敗,在併發量達到689時,有64個資源請求失敗 未經過,當前博客園系統登陸頁的最大訪問量應小於643
博客園系統登陸接口的最大併發量 在當前環境下能夠1000用戶併發,不會形成用戶請求失敗 在3s內逐漸提升併發量,當併發量達到1000時,請求資源仍所有成功 經過
博客園登陸頁的響應時間 在當前環境下用戶平均響應時長<2s 95%響應時長<= 5s 50th響應時間爲1.6s,95th爲22s 未經過
博客園登陸接口的響應時間 在當前環境下用戶平均響應時長<2s 95%響應時長<= 5s 50th響應時間 < 1s,95th < 1s 經過

測試總結

根據上述分析報告,本次性能測試爲經過制定要求,博客園系統登陸功能的最大併發量應小於643,爲保持性能,建議併發數小於500

五. 經常使用腳本api

5.1 併發量控制

  1. atOnceUsers(100) 使用100併發量測試目標服務器
  2. rampUsers(100) over (10 seconds) 按部就班的增大壓力,在10s中內線性增長用戶數達到最大壓力100併發量
  3. nothingFor(10 seconds) 等待10s
  4. constantUsersPerSec(rate) during(duration) 在指定duration內,以固定頻率注入用戶,每秒注入rate個用戶,默認固定間隔
  5. constantUsersPerSec(rate) during(duration) randomized 與上面不一樣的是用戶以隨機間隔注入
  6. rampUsersPerSec(rate1) to (rate2) during(duration) 在指定duration內,以遞增頻率注入用戶,每秒注入 rate1 ~ rate2 個用戶

5.2 用戶行爲控制

  1. .exec() 實際的用戶行爲
  2. .pause(20) 用戶滯留20s,模擬用戶思考或者瀏覽內容
  3. .pause(min: Duration, max: Duration) 用戶隨機滯留,滯留時間在min ~ max 之間

5.3 流程控制

  1. repeat(time, counterName) 內置循環器
  2. foreach(seq, elem, counterName) foreach循環器
  3. csv("file").random 建立填充器
  4. doIf("", "") 判斷語句
相關文章
相關標籤/搜索