1. Gatling — Java/Scala DSL
# Cài đặt
# Option 1: Gatling bundle
wget https://repo1.maven.org/maven2/io/gatling/highcharts/gatling-charts-highcharts-bundle/3.11.5/gatling-charts-highcharts-bundle-3.11.5.zip
# Option 2: Maven plugin
mvn gatling:test
# Option 3: Gradle plugin
gradle gatlingRun
Gatling Simulation (Java DSL)
// src/test/java/simulations/ProductLoadTest.java
import io.gatling.javaapi.core.*;
import io.gatling.javaapi.http.*;
import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.*;
public class ProductLoadTest extends Simulation {
HttpProtocolBuilder httpProtocol = http
.baseUrl("https://api.example.com")
.acceptHeader("application/json")
.contentTypeHeader("application/json")
.userAgentHeader("Gatling/LoadTest");
// Feeder: test data
FeederBuilder<String> userFeeder = csv("users.csv").random();
ScenarioBuilder browseProducts = scenario("Browse Products")
.feed(userFeeder)
.exec(
http("Login")
.post("/api/auth/login")
.body(StringBody("{\"email\":\"#{email}\",\"password\":\"#{password}\"}"))
.check(jsonPath("$.accessToken").saveAs("token"))
)
.pause(1, 3)
.exec(
http("List Products")
.get("/api/products?page=1&limit=20")
.header("Authorization", "Bearer #{token}")
.check(
status().is(200),
jsonPath("$.data[*].id").findAll().saveAs("productIds"),
responseTimeInMillis().lt(300)
)
)
.pause(2, 5)
.exec(
http("Product Detail")
.get("/api/products/#{productIds.random()}")
.header("Authorization", "Bearer #{token}")
.check(status().is(200))
);
{
setUp(
browseProducts.injectOpen(
rampUsers(100).during(120), // Ramp to 100 users in 2 min
constantUsersPerSec(50).during(300), // 50 users/sec for 5 min
rampUsers(500).during(120) // Ramp to 500 users in 2 min
)
).protocols(httpProtocol)
.assertions(
global().responseTime().percentile3().lt(500), // p95 < 500ms
global().responseTime().percentile4().lt(2000), // p99 < 2s
global().failedRequests().percent().lt(1.0) // < 1% failures
);
}
}
Gatling Report
Gatling tự động generate HTML report với:
├── Response time distribution (histogram)
├── Response time percentiles over time
├── Requests per second chart
├── Active users over time
├── Response time vs request/sec
└── Assertions results (pass/fail)
Output: target/gatling/productloadtest-{timestamp}/index.html
2. Artillery — YAML-based Testing
# Cài đặt
npm install -g artillery
artillery --version
# Chạy test
artillery run test.yml
artillery run --output report.json test.yml
artillery report report.json # Generate HTML report
Artillery Test Definition__HTMLTAG_80___
# tests/load/artillery-test.yml
config:
target: "https://api.example.com"
phases:
- duration: 120 # 2 min ramp up
arrivalRate: 5
rampTo: 50
name: "Warm up"
- duration: 300 # 5 min sustain
arrivalRate: 50
name: "Sustained load"
- duration: 120 # 2 min spike
arrivalRate: 200
name: "Spike"
defaults:
headers:
Content-Type: "application/json"
plugins:
expect: {}
metrics-by-endpoint: {}
ensure:
thresholds:
- http.response_time.p95: 300 # p95 < 300ms
- http.response_time.p99: 1000 # p99 < 1s
- http.codes.500: 0 # Zero 500 errors
payload:
path: "data/users.csv"
fields:
- "email"
- "password"
scenarios:
- name: "User Journey"
weight: 70 # 70% traffic
flow:
- post:
url: "/api/auth/login"
json:
email: "{{ email }}"
password: "{{ password }}"
capture:
- json: "$.accessToken"
as: "token"
expect:
- statusCode: 200
- think: 2
- get:
url: "/api/products?page=1&limit=20"
headers:
Authorization: "Bearer {{ token }}"
capture:
- json: "$.data[0].id"
as: "productId"
expect:
- statusCode: 200
- hasProperty: "data"
- think: 3
- get:
url: "/api/products/{{ productId }}"
headers:
Authorization: "Bearer {{ token }}"
expect:
- statusCode: 200
- name: "Search"
weight: 30 # 30% traffic
flow:
- get:
url: "/api/search?q=laptop&limit=10"
expect:
- statusCode: 200
# tests/load/artillery-test.yml
config:
target: "https://api.example.com"
phases:
- duration: 120 # 2 min ramp up
arrivalRate: 5
rampTo: 50
name: "Warm up"
- duration: 300 # 5 min sustain
arrivalRate: 50
name: "Sustained load"
- duration: 120 # 2 min spike
arrivalRate: 200
name: "Spike"
defaults:
headers:
Content-Type: "application/json"
plugins:
expect: {}
metrics-by-endpoint: {}
ensure:
thresholds:
- http.response_time.p95: 300 # p95 < 300ms
- http.response_time.p99: 1000 # p99 < 1s
- http.codes.500: 0 # Zero 500 errors
payload:
path: "data/users.csv"
fields:
- "email"
- "password"
scenarios:
- name: "User Journey"
weight: 70 # 70% traffic
flow:
- post:
url: "/api/auth/login"
json:
email: "{{ email }}"
password: "{{ password }}"
capture:
- json: "$.accessToken"
as: "token"
expect:
- statusCode: 200
- think: 2
- get:
url: "/api/products?page=1&limit=20"
headers:
Authorization: "Bearer {{ token }}"
capture:
- json: "$.data[0].id"
as: "productId"
expect:
- statusCode: 200
- hasProperty: "data"
- think: 3
- get:
url: "/api/products/{{ productId }}"
headers:
Authorization: "Bearer {{ token }}"
expect:
- statusCode: 200
- name: "Search"
weight: 30 # 30% traffic
flow:
- get:
url: "/api/search?q=laptop&limit=10"
expect:
- statusCode: 200
Artillery Plugins
# Plugin: publish metrics to Datadog
config:
plugins:
publish-metrics:
- type: datadog
apiKey: "{{ $processEnvironment.DD_API_KEY }}"
prefix: "artillery."
tags:
- "env:staging"
- "test:load"
# Plugin: CloudWatch
cloudwatch:
namespace: "Artillery/LoadTests"
3. Compare k6 vs Gatling vs Artillery
| Criteria_ | k6 | _Gatling | Artillery_ |
|---|---|---|---|
| Language language | JavaScript | Java/Scala/Kotlin | YAML + JS |
| Runtime | Go | JVM (Scala) | Node.js |
| Performance_ | _Very High | High | Medium average |
| Learning curve | _Low | Medium | Very low |
| CI/CD integration | Excellent_ | Good (Maven/Gradle) | Good (npm) |
| Distributed | k6 Operator (K8s) | Enterprise | Artillery Pro |
| Browser testing | k6 browser module_ | No | Playwright plugin |
| Report | JSON/Prometheus | Beautiful HTML | JSON/HTML |
| Cloud SaaS | _Grafana Cloud k6 | Gatling Enterprise | Artillery Pro |
| Ecosystem | Grafana, Prometheus | JVM ecosystem | Node.js ecosystem |
| Best for | DevOps/SRE teams | Java/Enterprise | Quick API tests |
4. When to use which tool?
Chọn k6 khi:
✅ Team đã dùng Grafana ecosystem
✅ Cần tích hợp CI/CD mạnh
✅ Cần distributed testing trên K8s
✅ Muốn viết test bằng JavaScript
Chọn Gatling khi:
✅ Team Java/Scala/Spring Boot
✅ Cần report HTML sẵn đẹp
✅ Enterprise environment
✅ Complex scenario scripting
Chọn Artillery khi:
✅ Team nhỏ, cần MVP nhanh
✅ API testing đơn giản
✅ Prefer YAML over code
✅ Node.js application testing
5. Summary
- Gatling: Mature, JVM-based, excellent reports, strong enterprise adoption
- Artillery: YAML-first, lowest learning curve, good for quick API tests
- k6: Best developer experience, Grafana ecosystem, distributed via K8s
- There is no "best" tool — choose based on team skills, tech stack, and requirements
The next article will learn API Performance Testing — REST, GraphQL, gRPC, WebSocket.