In a previous blog post we made an API with spray. Now we're going to load test it. For this, we will use http://gatling.io/#/. In a scala class we can write exactly what and how we want to run the test. In this test, we will do a post to our API and create a new robot called C3PO. We will do this 1000 times per second and keep doing this for 10 seconds. For a total of 10000 C3POs! RobotsLoadTest.scala:

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

class RobotsLoadTest extends Simulation {
    val baseUrl = "http://localhost:8080" //We need to have our API running here

    val httpProtocol = http
        .baseURL(baseUrl)
        .inferHtmlResources()
        .acceptEncodingHeader("gzip,deflate")
        .contentTypeHeader("application/json")
        .userAgentHeader("Apache-HttpClient/4.1.1 (java 1.5)")

    val s = scenario("Simulation")
        .exec(http("request_0")
        .post("/robots")
        .body(StringBody("""{
                        |  "name": "C3PO",
                        |  "amountOfArms": 2
                        |}""".stripMargin))
        )

    setUp(s.inject(constantUsersPerSec(1000) during(10 seconds))).protocols(httpProtocol)
}

If you want to use maven, there is a nice Gatling plugin. But of course we'd rather use gradle. This works fine too, since we can just run Gatling as a java program. build.gradle:

apply plugin: 'scala'

version = '1.0'

repositories {
    mavenCentral()
}

dependencies {
    ext.gatlingVersion = '2.1.7'
    compile group: 'io.gatling', name: 'gatling-app', version: gatlingVersion
    compile group: 'io.gatling', name: 'gatling-recorder', version: gatlingVersion
    compile group: 'io.gatling.highcharts', name: 'gatling-charts-highcharts', version: gatlingVersion
}

task gatling(dependsOn: 'compileTestScala') << {
    javaexec {
        main = 'io.gatling.app.Gatling'
        classpath = sourceSets.test.output + sourceSets.test.runtimeClasspath
            args    '-sf', sourceSets.test.output,            //source folder
                    '-bf', sourceSets.test.output.classesDir, //target folder where gatling will compile the simulation
                    '-s', 'RobotsLoadTest',                   //The simulation to run
                    '-rf', 'build/reports/gatling'            //place to put the report
    }
}

We can run this test with gradle gatling to get our results.

================================================================================
---- Global Information --------------------------------------------------------
> request count                                      10000 (OK=10000  KO=0     )
> min response time                                      0 (OK=0      KO=-     )
> max response time                                    455 (OK=455    KO=-     )
> mean response time                                    11 (OK=11     KO=-     )
> std deviation                                         39 (OK=39     KO=-     )
> response time 50th percentile                          4 (OK=4      KO=-     )
> response time 75th percentile                          7 (OK=7      KO=-     )
> mean requests/sec                                975.515 (OK=975.515 KO=-    )
---- Response Time Distribution ------------------------------------------------
> t < 800 ms                                         10000 (100%)
> 800 ms < t < 1200 ms                                   0 (  0%)
> t > 1200 ms                                            0 (  0%)
> failed                                                 0 (  0%)
================================================================================

Reports generated in 2s.
Please open the following file: build/reports/gatling/robotsloadtest-1438856116217/index.html

This is already a pretty neat report. Opening the html file will be even prettier. Seems like our API can handle 1000 requests/second at least fine. Going higher we'll have to take some other things into consideration.

  • The amount of connection we can open at once.
  • We're running both the API and gatling on the same machine now.
  • If we run it on another machine, the network may become the bottleneck
  • Gatling may be the bottleneck.

You can find the whole source here.

shadow-left