使用 Gateling 進行性能測試

Gatling 是一個簡便的性能測試工具,用它編寫性能測試腳本速度快易上手。本文將深入探究 Gatling 的功能以及如何更好地使用。

使用 Gateling 進行性能測試


在程序部署到生產環境前,有多少人會創建自動化性能測試?通常,開發人員更重視功能測試,至少會進行一些簡單的單元測試和集成測試。但是與未檢測到的業務錯誤相比,有時候性能洩露造成的問題更嚴重。因為後者會影響整個系統,不僅僅是某個業務流程。

就個人而言,我一直對自己開發的程序進行性能測試,但是從來沒有把它作為持續集成的一部分運行。當然,這是幾年前的情況,那時候我的知識和經驗都略顯不足。最近,我開始對性能測試相關的主題非常感興趣,部分原因是公司的應用程序存在性能問題。問題的關鍵是找到合適的工具。也許很多人聽說過 JMeter,這裡會介紹它的競品——Gatling。它會生成各種內容豐富的報告,其中包含了測試用例執行過程中收集的所有指標。這些功能比 JMeter 似乎更好。

在開始介紹 Gatling 之前,讓我們先聊聊理論。首先,性能測試有兩種類型:負載測試和壓力測試。負載測試會驗證,在特定時間內有大量客戶端同時發起請求情況下的系統功能。這種測試的主要目標是模擬生產環境中可能出現的流量。壓力測試會執行負載測試,把應用程序推向極限,查看重負載情況下程序的表現。

Gatling是什麼?

Gatling 是一個用 Scala 編寫的負載測試工具,功能強大。它完全支持 HTTP 協議,也可以用來測試 JDBC 連接和 JMS。使用 Gatling 時,需要用 Scala dsl 代碼定義測試場景。值得一提的是,Gatling 生成的 HTML 負載報告內容全面,並且提供了 Gradle、Maven 和 Jenkins 插件方便集成。

構建示例應用

開始測試前,需要準備測試應用。示例程序非常簡單,源代碼可以在 GitHub 上找到(github.com/piomin/sample-gatling-load-tests)。它提供了一組 CRUD 操作的 RESTful HTTP API,在可以數據庫中新增和搜索 Entity。數據庫用 Postgres,基於 Spring Boot 構建,使用Spring Data 實現持久層。

plugins {
id 'org.springframework.boot' version '1.5.9.RELEASE'
}
dependencies {
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa'
compile group: 'org.postgresql', name: 'postgresql', version: '42.1.4'
testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test'
}

Person entity映射到 person 表。

@Entity
@SequenceGenerator(name = "seq_person", initialValue = 1, allocationSize = 1)
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_person")
private Long id;
@Column(name = "first_name")

private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "birth_date")
private Date birthDate;
@Embedded
private Address address;
// ...
}

數據庫連接設置和 Hibernate 屬性配置在 application.yml 中。

spring:
application:
name: gatling-service
datasource:
url: jdbc:postgresql://192.168.99.100:5432/gatling
username: gatling
password: gatling123
jpa:
properties:
hibernate:
hbm2ddl:
auto: update
server:
port: 8090

正如之前提到的,示例程序提供了在數據庫中添加、搜索 person 的 API,下面是 Spring REST controller 實現。

@RestController
@RequestMapping("/persons")
public class PersonsController {
private static final Logger LOGGER = LoggerFactory.getLogger(PersonsController.class);
@Autowired
PersonsRepository repository;
@GetMapping
public List
<person> findAll() {
return (List
<person>) repository.findAll();
}
@PostMapping
public Person add(@RequestBody Person person) {
Person p = repository.save(person);

LOGGER.info("add: {}", p.toString());
return p;
}
@GetMapping("/{id}")
public Person findById(@PathVariable("id") Long id) {
LOGGER.info("findById: id={}", id);
return repository.findOne(id);
}
}
/<person>/<person>

運行數據庫

開發示例程序的下一步是運行數據庫,最合適的方式是 Docker image。下面的 Docker 命令會啟動一個 Postgres container,完成 gatling 用戶和數據庫初始化。

docker run -d --name postgres -e POSTGRES_DB=gatling -e POSTGRES_USER=gatling -e POSTGRES_PASSWORD=gatling123 -p 5432:5432 postgres

設計測試場景

每個 Gatling test suite 都要繼承 Simulation 類,使用 Gatling Scala DSL 聲明一系列測試場景。我們的目標是啟動30個客戶端,同時發送1000次請求。首先,客戶端通過 POST /persons 方法向數據庫添加 person。然後,調用 GET /persons/{id}搜索 person。總共嚮應用程序發送6萬次請求:3萬次 POST,3萬次 GET。下面代碼展示了測試場景,非常簡單。在 src/test/scala 目錄下可以找到 ApiGatlingSimulationTest。

class ApiGatlingSimulationTest extends Simulation {
val scn = scenario("AddAndFindPersons").repeat(1000, "n") {
exec(
http("AddPerson-API")
.post("http://localhost:8090/persons")
.header("Content-Type", "application/json")
.body(StringBody("""{"firstName":"John${n}","lastName":"Smith${n}","birthDate":"1980-01-01", "address": {"country":"pl","city":"Warsaw","street":"Test${n}","postalCode":"02-200","houseNo":${n}}}"""))

.check(status.is(200))
).pause(Duration.apply(5, TimeUnit.MILLISECONDS))
}.repeat(1000, "n") {
exec(
http("GetPerson-API")
.get("http://localhost:8090/persons/${n}")
.check(status.is(200))
)
}
setUp(scn.inject(atOnceUsers(30))).maxDuration(FiniteDuration.apply(10, "minutes"))
}

為了在項目中啟用 Gatling 框架,還需要在 Gradle 構建文件中添加依賴。

testCompile group: 'io.gatling.highcharts', name: 'gatling-charts-highcharts', version: '2.3.0'

運行測試

使用 Gateling 進行性能測試


通過一些 Gradle 插件可以在項目構建期間運行測試。但是,也可用 io.gatling.app.Gatling 類定義簡單的 gradle 任務。

task loadTest(type: JavaExec) {
dependsOn testClasses
description = "Load Test With Gatling"
group = "Load Test"
classpath = sourceSets.test.runtimeClasspath
jvmArgs = [
"-Dgatling.core.directory.binaries=${sourceSets.test.output.classesDir.toString()}"
]
main = "io.gatling.app.Gatling"
args = [
"--simulation", "pl.piomin.services.gatling.ApiGatlingSimulationTest",
"--results-folder", "${buildDir}/gatling-results",
"--binaries-folder", sourceSets.test.output.classesDir.toString(),
"--bodies-folder", sourceSets.test.resources.srcDirs.toList().first().toString() + "/gatling/bodies",
]
}

使用 gradle loadTest 執行定義好的 Gradle 任務。當然,運行測試之前需要啟動應用程序,在 IDE 中啟動 main class pl.piomin.services.gatling.ApiApplication 或者執行 java -jar build/libs/sample-load-test-gatling.jar 命令。

測試報告

測試執行完畢會以文本形式打印報告。

================================================================================
---- Global Information --------------------------------------------------------
> request count 60000 (OK=60000 KO=0 )
> min response time 2 (OK=2 KO=- )
> max response time 1338 (OK=1338 KO=- )
> mean response time 80 (OK=80 KO=- )
> std deviation 106 (OK=106 KO=- )
> response time 50th percentile 50 (OK=50 KO=- )

> response time 75th percentile 93 (OK=93 KO=- )
> response time 95th percentile 253 (OK=253 KO=- )
> response time 99th percentile 564 (OK=564 KO=- )
> mean requests/sec 319.149 (OK=319.149 KO=- )
---- Response Time Distribution ------------------------------------------------
> t < 800 ms 59818 (100%) > 800 ms < t < 1200 ms 166 ( 0%) > t > 1200 ms 16 ( 0%)
> failed 0 ( 0%)
================================================================================

但是,Gatling 最擅長的是報告圖表。生成的 HTML 報告在 build/gatling-results 目錄下。第一個報告展示了全局信息,包含請求總數和最大響應時間(百分比)。例如,95%的 GetPerson API 請求的最大響應時間為206ms。

使用 Gateling 進行性能測試



可以在報告中查看所有請求,也可以過濾結果,只查看選定的 API。下面的圖片只展示了 GetPerson API。

使用 Gateling 進行性能測試



這張圖展示了平均響應時間百分比。

使用 Gateling 進行性能測試



這張圖中的時間軸表示平均響應時間。此外,該時間軸還按百分比展示了統計信息。

使用 Gateling 進行性能測試



這張圖展示了應用程序每秒鐘成功處理的請求數。

使用 Gateling 進行性能測試



分享到:


相關文章: