构建可执行的JAR包用于Gatling负载测试。

18

我是Gatling(2.1.2)的新手,想做一个小的原型项目展示给我的同事们看。

根据快速入门页面,有几种方法可以使用Gatling运行模拟:

  1. 将Gatling打包解压到文件夹中,并将模拟文件放入“user-files / simulations”文件夹中。bin/gatling.sh将编译和运行模拟文件。
  2. 使用gatling-maven-plugin Maven插件来执行模拟。
  3. 创建一个具有gatling-highcharts-maven-archetype的项目,并运行引擎类。

但我发现以下问题:

对于第一种方法,很难为模拟类添加依赖项。我必须找出需要的JAR并将它们放置在lib文件夹中。

对于第二种方法,需要安装Maven。

对于第三种方法,仅能从IDE中运行。

我只想要一个简单的可执行JAR文件,并将所有依赖项打包在一起(我的模拟、Gatling和第三方库),并从任何机器(如EC2实例)运行它。有没有办法实现这一点呢?

更新1:

我尝试了第三种方法,将所有项目文件从test文件夹移动到main中,并使用maven-assembly-plugin构建带依赖项的jar。当我尝试运行该文件时,得到以下错误:

Exception in thread "main" java.lang.ExceptionInInitializerError
    at Engine$.delayedEndpoint$Engine$1(Engine.scala:7)
    at Engine$delayedInit$body.apply(Engine.scala:4)
    at scala.Function0$class.apply$mcV$sp(Function0.scala:40)
    at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
    at scala.App$$anonfun$main$1.apply(App.scala:76)
    at scala.App$$anonfun$main$1.apply(App.scala:76)
    at scala.collection.immutable.List.foreach(List.scala:381)
    at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:35)
    at scala.App$class.main(App.scala:76)
    at Engine$.main(Engine.scala:4)
    at Engine.main(Engine.scala)
Caused by: java.nio.file.FileSystemNotFoundException
    at com.sun.nio.zipfs.ZipFileSystemProvider.getFileSystem(ZipFileSystemProvider.java:171)
    at com.sun.nio.zipfs.ZipFileSystemProvider.getPath(ZipFileSystemProvider.java:157)
    at java.nio.file.Paths.get(Paths.java:143)
    at io.gatling.core.util.PathHelper$.uri2path(PathHelper.scala:32)
    at IDEPathHelper$.<init>(IDEPathHelper.scala:7)
    at IDEPathHelper$.<clinit>(IDEPathHelper.scala)
    ... 11 more

我猜这与 Gatling 的配置有关,但不知道出了什么问题。


如果你想建立一个 PoC,为什么不先坚持使用官方支持的部署策略呢? - Stephane Landelle
@StephaneLandelle,我实际上已经尝试了官方的策略,这就是我发现我不得不将所有的jar文件放入lib文件夹中的原因。我只想知道是否有可能构建一个可运行的JAR文件,以及原因。 - stackoverflower
@Philippe,你可以尝试使用我在问题中提到的方法1。你需要做的是解压Gatling捆绑包zip文件,并将你的场景scala文件粘贴到${GATLING}/user-files/simulations文件夹中。任何依赖的jar都应该放在${GATLING}/lib中(如果捆绑包中没有该文件夹,则需要创建)。然后你可以通过${GATLING}/bin/gatlin.sh来运行Gatling。文件会告诉你所有的工作原理。 - stackoverflower
这是目前最佳实践,直到Gatling提供一个可独立运行的文件,这正是我想要的。 - stackoverflower
7个回答

12

我也想尝试类似的事情,但是我不能像你一样使用Maven。我会尝试回忆一下我当时是怎么做的。

1) 我配置了maven-assembly-plugin以生成带有依赖项的单个JAR文件,如下所示:

<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
    </configuration>
</plugin>

您需要确保所需的所有库(gatling、scala runtime、zinc编译器)都存在于您的结果类路径中。

2) 检查您的依赖范围,因为默认情况下 Maven 仅打包 scope=compile 定义的类。最简单的方法可能是不使用测试依赖项。

3) 创建一个启动脚本,例如 launch.sh。它应该包含类似以下内容:

#!/bin/sh
USER_ARGS="-Dsomething=$1"
COMPILATION_CLASSPATH=`find -L ./target -maxdepth 1 -name "*.jar" -type f -exec printf :{} ';'`
JAVA_OPTS="-server -XX:+UseThreadPriorities -XX:ThreadPriorityPolicy=42 -Xms512M -Xmx2048M -XX:+HeapDumpOnOutOfMemoryError -XX:+AggressiveOpts -XX:+OptimizeStringConcat -XX:+UseFastAccessorMethods -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false ${JAVA_OPTS}"
java $JAVA_OPTS $USER_ARGS -cp $COMPILATION_CLASSPATH io.gatling.app.Gatling -s your.simulation.FullClassName

解释一下,我以Gatling自己的启动脚本为灵感。注意主要是在类路径参数定义中存在target目录。

4)将编译后的target目录和launch.sh编译到一个目录中并分发它(例如作为归档文件)。然后,您可以通过执行./launch.sh来运行场景。

我知道这不是标准解决方案,但对我有用。希望它也能帮助您。如果您有任何问题或改进提示,请与我们分享。


抱歉回复晚了。我最终做的与这几乎相同。希望Gatling团队能够官方支持这个功能。 - stackoverflower
3
我该如何指定模拟类列表?-sf不起作用,因为它需要文件夹路径而不是捆绑在jar包中的包路径。 - Amit Kumar Gupta

7

我知道现在可能有点晚了,但是我遇到了一个类似的问题,与此相关,但是我使用的是gradle而不是maven。我猜想方法应该是一样的,结合第一个解决方案和自己的一些东西。

首先,定义一个带有Gatling依赖项和构建fatjar的任务的Gradle构建文件。

apply plugin: 'scala'
version 0.1

dependencies {
  compile group: 'io.gatling', name: 'gatling-test-framework', version: '2.1.7'
  compile group: 'com.typesafe.akka', name: 'akka-actor_2.11', version: '2.4.7'
  compile group: 'org.scala-lang', name: 'scala-library', version: '2.11.7'
}

repositories{
   mavenCentral()
   mavenLocal()
}


task fatJar(type: Jar) {
   manifest {
       attributes 'Implementation-Title': 'Preparing test',  
          'Implementation-Version': version,
          'Main-Class': 'io.gatling.app.Gatling'
   }
   baseName = project.name + '-all'
      from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } {
        exclude 'META-INF/MANIFEST.MF'
        exclude 'META-INF/*.SF'
        exclude 'META-INF/*.DSA'
        exclude 'META-INF/*.RSA'

   }
   with jar
}

该任务被执行为

gradle clean build fatJar

将生成一个自包含的jar文件,该文件将默认运行Gatling主类。因此,使用标准的'-s'参数告诉它要运行哪个测试。

因此,最后一步是创建(如果需要)一个脚本来运行它。我会“借用”第一个评论中的脚本并稍作更改。

#!/bin/sh

if [ -z "$1" ];
then
    echo "Test config tool"
    echo
    echo "Running Parameters : "
    echo
    echo " <Config file> : Test definition file. Required"
    echo
   exit 0;
 fi

USER_ARGS="-DCONFIG_FILE=$1"
JAVA_OPTS="-server -XX:+UseThreadPriorities -XX:ThreadPriorityPolicy=42 -Xms512M -Xmx2048M -XX:+HeapDumpOnOutOfMemoryError -XX:+AggressiveOpts -XX:+OptimizeStringConcat -XX:+UseFastAccessorMethods -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false ${JAVA_OPTS}"
java $JAVA_OPTS $USER_ARGS -jar test-project-all-0.1.jar -s FunctionalTestSimulation -nr

在我的情况下,我会使用易于配置的不同参数运行相同的测试,以便我的模拟始终保持一致。我的所有scala文件都是通过gradle编译并打包成jar文件,这意味着它们在类路径中,将“FunctionalTestSimulation”名称更改为脚本变量可以轻松地使此脚本适应更通用的内容。
猜测用Maven版本也很容易。
希望能帮助到某些人。
更新文件夹结构草稿后再次更新。
test-project
    |_ build.gradle
    |_ src
        |_ main
            |_ scala
            |_ resources
    |_ runSimulation.sh
    |_ configFile.conf

如果有时间,我会提供一个链接到我的GitHub,其中包含一个可用的版本。

祝好运!


1
这真的很有帮助,谢谢。有一件小事,我看到你在顶部以不同格式两次导入了scala-library。你可以删除其中一个。 - JamesWillett
谢谢,我没意识到! - kszosze
你能否分享一下适用于这个Gradle脚本的项目目录结构?比如,你的测试文件和资源文件存放在哪里? - Alex
好的,我会准备一些示例代码并将其放在我的Github上。但是需要一些时间,因为这些天我非常忙。可以吗?如果你很着急,只需给我发电子邮件,我会尽力解释。 - kszosze
为了让脚本生成报告,请移除-nr并将"compile "io.gatling.highcharts:gatling-charts-highcharts:2.3.0""添加到Gradle依赖项中。 - Pashec
这里出现了"com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'akka.stream'"的错误提示,原因可能是在构建fat jar文件时需要将多个包含akka配置信息的"reference.conf"文件合并成一个。 - Alex

5

您可以始终创建一个简单的Java类,使用Gatling.fromArgs启动Gatling。通过这种设置,您可以将所有内容放在一个可执行的jar文件中。让这个类成为jar的mainClass,而不是"io.gatling.app.Gatling"。下面是一个针对Scala仿真类"my.package.MySimulation"的示例。

import scala.Option;
import io.gatling.app.Gatling;
import io.gatling.core.scenario.Simulation;

public class StartSimulation {

  public static void main(String[] args) {
    Gatling.fromArgs(new String[]{}, new Option<Class<Simulation>>() {

        private static final long serialVersionUID = 1L;

        @Override
        public int productArity() {
            return 0;
        }

        @Override
        public Object productElement(int arg0) {
            return null;
        }

        @SuppressWarnings("unchecked")
        @Override
        public Class<Simulation> get() {
            try {
                return (Class<Simulation>) Class.forName("my.package.MySimulation");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        public boolean isEmpty() {
            return false;
        }

        @Override
        public boolean canEqual(Object o) {
            return false;
        }
    });
  }
}

感谢您的回答。问题更多地涉及依赖关系。我最终所做的是编写一个自定义的主类,就像您一样,并使用Maven将项目打包成带有依赖项的可执行JAR文件。 - stackoverflower
不幸的是,fromArgs方法在2.2.3版本中被标记为io.gatling的私有方法,因此要使用这个技巧,现在需要添加类似以下内容的代码:package io.gatling import io.gatling.app.{Gatling, SelectedSimulationClass} object GatlingHack { def fromArgs(args: Array[String], selectedSimulationClass: SelectedSimulationClass): Int = Gatling.fromArgs(args, selectedSimulationClass) } - Magnus Reftel
1
请注意,正如Stephane Landelle在将fromArgs方法设为私有之前几天所指出的那样,Gatling并不意味着以这种方式嵌入:https://groups.google.com/d/msg/gatling/387pDAweZEY/Va6TsErHAAAJ - Magnus Reftel

2
我遇到了类似的问题,我通过以下方式解决:
在 Gatling 包内部,有一个 bin/ 目录,打开 gatling.sh 文件。你会看到它简单地将某些配置添加到类路径中,然后运行 gatling-compiler-.jar 中的 io.gatling.app.Gatling 类。所以,你只需要制作一个包含编译器的 jar 包,将配置和测试添加到类路径中,然后运行 io.gatling.app.Gatling。
步骤如下:
添加编译器依赖:
<dependency>
        <groupId>io.gatling</groupId>
        <artifactId>gatling-compiler</artifactId>
        <version>${gatling.version}</version>
    </dependency

创建包含依赖项的jar文件:
  <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.4.1</version>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
                <finalName>${project.build.finalName}</finalName>
            </configuration>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

创建测试jar包(其中包含您的Gatling测试)。
 <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <executions>
                <execution>
                    <goals>
                        <goal>test-jar</goal>
                    </goals>
                    <configuration>
                        <excludes>
                            <exclude>src/test/resources/*</exclude>
                        </excludes>
                        <finalName>${project.build.finalName}</finalName>
                    </configuration>
                </execution>
            </executions>
        </plugin>

创建一个配置文件的包。你可以使用Maven Assembly来完成这个任务。通常我会创建一个单独的模块来处理不同环境下的打包。这个包含了你的,以及其他资源文件,包括测试数据。
现在你基本上有三个包:,和。
解压缩,将和复制到同一个文件夹中。
在这个文件夹中,你需要创建一个文件夹,只需保留空文件夹即可。在我的情况下,这是必需的。我认为你可以在中进行一些更改。但我不确定如何操作。
运行:
java -cp ".:application-test.jar:application.jar" io.gatling.app.Gatling  

0

对我来说,这很有效。


task fatJar(type: Jar, dependsOn: ['gatlingClasses', 'processResources']) {
  group =  "build"
  manifest {
    attributes 'Implementation-Title': project.name,
      'Implementation-Version': project.version,
      'Main-Class': 'myPackage.MyMainClass'
  }

  exclude 'META-INF/MANIFEST.MF'
  exclude 'META-INF/*.SF'
  exclude 'META-INF/*.DSA'
  exclude 'META-INF/*.RSA'

  duplicatesStrategy = DuplicatesStrategy.EXCLUDE

  archiveClassifier = "all"

  from files(sourceSets.main.output.classesDirs)
  from files(sourceSets.gatling.output)
  from {
    configurations.gatlingRuntimeClasspath
      .filter { it.exists() }
      .collect { it.isDirectory() ? it : zipTree(it) }
  }


  with jar
}


修改版的https://medium.com/@suman.maity112/run-gatling-scenarios-as-executable-jar-bfe32c3d9af5

-1

我最近写了一篇关于为Gatling测试创建可版本化、自包含(fat-/uber-)JAR的博客,源代码可以在jamietanna/fat-gatling-jar中找到。

对于一个Maven项目,步骤如下。

你需要做的主要事情是添加gatling-charts-highcharts依赖项:

<project>
    <!-- ... -->
    <dependencies>
        <dependency>
            <groupId>io.gatling.highcharts</groupId>
            <artifactId>gatling-charts-highcharts</artifactId>
            <version>${gatling.version}</version>
        </dependency>
    </dependencies>
</project>

接下来,您需要确保您的Gatling场景/模拟位于src/main而不是src/test

最后,您可以使用maven-shade-plugin构建可执行的JAR文件,该文件使用Gatling的CLI运行程序作为mainClass

<project>
    <!-- ... -->
    <build>
        <plugins>
            <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-shade-plugin</artifactId>
              <version>3.1.1</version>
              <configuration>
                <filters>
                  <!-- https://dev59.com/qHNA5IYBdhLWcg3wWsUA#6743609 -->
                  <filter>
                    <artifact>*:*</artifact>
                    <excludes>
                      <exclude>META-INF/*.DSA</exclude>
                      <exclude>META-INF/*.SF</exclude>
                      <exclude>META-INF/*.RSA</exclude>
                    </excludes>
                  </filter>
                </filters>
              </configuration>
              <executions>
                <execution>
                  <phase>package</phase>
                  <goals>
                    <goal>shade</goal>
                  </goals>
                  <configuration>
                    <transformers>
                      <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>io.gatling.app.Gatling</mainClass>
                      </transformer>
                    </transformers>
                  </configuration>
                </execution>
              </executions>
            </plugin>
        </plugins>
    </build>
</project>  

-1

我使用 IntelliJ Idea,通过右键单击 scala 文件夹 > 标记目录为 > 测试源根。现在执行 "Engine",一切都会很好!


如果将目录标记为 sources root 而不是 test,这也适用。方便快速运行测试的方式,我想。 - breakspirit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接