1. 简介

在本教程中,我们将了解如何使用 Gatling 进行分布式性能测试。我们将创建一个简单的应用程序用于测试,理解为什么需要进行分布式性能测试,并深入探讨 Gatling 提供的分布式支持。

2. 使用 Gatling 进行性能测试

性能测试是一种评估系统在特定负载下的响应性和稳定性的测试实践。常见的性能测试类型包括:负载测试、压力测试、浸泡测试、峰值测试等,每种测试都有其特定的目标。

然而,无论哪种性能测试,核心都是模拟负载。像 GatlingJMeterK6 这样的工具可以帮助我们实现这一点。但在此之前,我们需要一个可测试的应用。

我们接下来会为这个应用创建一个简单的负载模型。

2.1. 创建一个应用

本教程中,我们使用 Spring CLI 创建一个简单的 Spring Boot Web 应用:

spring init --dependencies=web my-application

然后,我们创建一个简单的 REST API,用于返回一个随机数:

@RestController
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @GetMapping("/api/random")
    public Integer getRandom() {
        Random random = new Random();
        return random.nextInt(1000);
    }
}

这个 API 没有什么特别的,每次调用都返回 0 到 999 之间的随机整数。

启动这个应用非常简单,使用 Maven 命令:

mvnw spring-boot:run

2.2. 创建负载模型

如果我们想把这个简单的 API 部署到生产环境,就需要确保它能够处理预期的负载并保持服务质量。这时就需要进行性能测试。

负载模型通常会定义一个或多个负载配置文件,以模拟真实使用场景

对于有用户界面的 Web 应用,定义合适的负载模型可能比较复杂。但对于我们的简单 API,可以假设一个负载分布。

Gatling 提供了 Scala DSL 来创建测试场景。我们先为前面创建的 API 编写一个基本的场景:

package randomapi

import io.gatling.core.Predef._
import io.gatling.core.structure.ScenarioBuilder
import io.gatling.http.Predef._
import io.gatling.http.protocol.HttpProtocolBuilder

class RandomAPILoadTest extends Simulation {
    val protocol: HttpProtocolBuilder = http.baseUrl("http://localhost:8080/")
    val scn: ScenarioBuilder = scenario("Load testing of Random Number API")
      .exec(
        http("Get Random Number")
          .get("api/random")
          .check(status.is(200))
      )

    val duringSeconds: Integer = Integer.getInteger("duringSeconds", 10)
    val constantUsers: Integer = Integer.getInteger("constantUsers", 10)
    setUp(scn.inject(constantConcurrentUsers(constantUsers) during (duringSeconds))
      .protocols(protocol))
      .maxDuration(1800)
      .assertions(global.responseTime.max.lt(20000), global.successfulRequests.percent.gt(95))
}

这个模拟脚本的关键点包括:

✅ 添加 Gatling DSL 必需的导入
✅ 定义 HTTP 协议配置
✅ 定义一个包含单个请求的场景
✅ 设置模拟参数:10 个并发用户,持续 10 秒

对于更复杂的 UI 应用,手动编写场景可能比较困难。幸运的是,Gatling 提供了一个 Recorder 工具,可以通过代理浏览器和服务器之间的交互来生成场景。它也支持导入 HAR 文件 来创建场景。

2.3. 执行模拟

现在我们可以执行这个负载测试了。将模拟脚本 RandomAPILoadTest.scala 放到目录 %GATLING_HOME%/user-files/simulations/randomapi/ 中。

启动 Gatling:

$GATLING_HOME/bin/gatling.sh

选择要运行的模拟脚本:

Choose a simulation number:
     [0] randomapi.RandomAPILoadTest

运行后会输出测试摘要:

Gatling Output

并在 %GATLING_HOME%/results 目录中生成 HTML 报告:

Gatling Report

3. 分布式性能测试

看起来不错,但别忘了,性能测试的目的是模拟真实世界的负载。对于热门应用来说,这个负载可能远高于我们刚刚测试的几百请求/秒。

如果负载需求远超单机能力怎么办?即使工具支持,操作系统和网络也可能成为瓶颈。

这时就需要将负载分布到多台机器上。但分布式测试也带来了挑战:

⚠️ 如何在多个节点间分配负载?
⚠️ 如何协调节点、处理错误?
⚠️ 如何汇总结果并生成统一报告?

典型的分布式测试架构采用 Master/Slave 模式:

Gatling Distributed Testing

当然,如果 Master 节点挂了怎么办?这属于分布式系统的一般性问题,这里不做深入探讨,但必须意识到这些风险。

4. 使用 Gatling 进行分布式测试

Gatling Frontline(企业版)内置了集群模式,支持在本地或云环境部署注入器。但 Frontline 不是开源的。

不过,我们仍然可以使用 Gatling 开源版实现分布式测试,只是需要自己处理大部分工作。

4.1. 环境准备

我们首先需要准备:

✅ 一台控制机(Controller)
✅ 多台远程工作机(Worker)

所有机器都需要安装相同版本的 Gatling,配置一致。

在控制机上设置环境变量:

HOSTS=( 192.168.x.x 192.168.x.x 192.168.x.x)
GATLING_HOME=/gatling/gatling-charts-highcharts-1.5.6
GATLING_SIMULATIONS_DIR=$GATLING_HOME/user-files/simulations
SIMULATION_NAME='randomapi.RandomAPILoadTest'
GATLING_RUNNER=$GATLING_HOME/bin/gatling.sh
GATLING_REPORT_DIR=$GATLING_HOME/results/
GATHER_REPORTS_DIR=/gatling/reports/

4.2. 分发负载脚本

将模拟脚本复制到所有工作机上。可以使用 scp 或写个脚本自动完成:

for HOST in "${HOSTS[@]}"
do
  scp -r $GATLING_SIMULATIONS_DIR/* $USER_NAME@$HOST:$GATLING_SIMULATIONS_DIR
done

Windows 用户可以使用 PuTTY + PSCP

4.3. 执行模拟

在所有工作机上几乎同时执行模拟脚本:

for HOST in "${HOSTS[@]}"
do
  ssh -n -f $USER_NAME@$HOST \
    "sh -c 'nohup $GATLING_RUNNER -nr -s $SIMULATION_NAME \
    > /gatling/run.log 2>&1 &'"
done

注意使用了 -nr 参数(no reports),因为我们只关心日志,稍后合并生成报告。

4.4. 收集结果

从各工作机收集日志文件:

for HOST in "${HOSTS[@]}"
do
  ssh -n -f $USER_NAME@$HOST \
    "sh -c 'ls -t $GATLING_REPORT_DIR | head -n 1 | xargs -I {} \
    mv ${GATLING_REPORT_DIR}{} ${GATLING_REPORT_DIR}report'"
  scp $USER_NAME@$HOST:${GATLING_REPORT_DIR}report/simulation.log \
    ${GATHER_REPORTS_DIR}simulation-$HOST.log
done

脚本逻辑是:登录远程机器,找到最新的报告目录,复制 simulation.log 并加上主机名后缀。

4.5. 生成合并报告

将所有日志合并,生成统一报告:

mv $GATHER_REPORTS_DIR $GATLING_REPORT_DIR
$GATLING_RUNNER -ro reports

最终报告看起来和单机测试一致:

Gatling Report Combined

可以看到,使用 3 台机器后请求数量几乎翻了三倍。虽然现实中很难做到线性扩展,但效果明显。

5. 性能测试扩展的注意事项

虽然分布式测试能扩展负载能力,但要注意:

优先垂直扩展:尽可能提升单机性能
操作系统限制:如 Linux 的文件句柄限制,可通过 ulimit 调整
资源瓶颈:网络带宽、CPU、内存等,云环境可轻松切换更强配置
测试脚本健壮性:不要假设所有请求都成功,断言要保守
断言精简:过多断言会影响吞吐量,只保留关键检查点

6. 结论

在本教程中,我们学习了如何使用 Gatling 实现分布式性能测试。从创建测试应用、编写模拟脚本,到在多台机器上执行测试并生成合并报告。

我们还讨论了分布式测试的必要性以及相关最佳实践。对于需要模拟高并发负载的项目,这套方法非常实用。


原始标题:Distributed Performance Testing with Gatling