Load test servers with unique requests.
.
":"
___:____ |"\/"|
,' `. \ /
| O \___/ |
~^~^~^~^~^~^~^~^~^~^~^~^~
ASCII art by Riitta Rasimus
Blowhole is a command line tool written in Go to perform unique requests for a given URL.
- Go 1.20+
go build .
# 100 requests for a /json resource served at localhost:8000
./blowhole -n 100 -url "http://localhost:8000/json"
# Results:
# ============================================================
# Test "unnamed" running - Run: RID001
#
# 2023/12/28 15:10:19
# Test: unnamed
# Run ID: RID001
# Requests target: 100
# Concurrency level: 1
#
# 100% |████████████████████████████████████████████████████████████| (100/100, 8 requests/s) [14s]
#
# 2023/12/28 15:10:33
# Requests sent: 100
# Average RPS: 7
# Response codes received:
# 1xx: 0 | 2xx: 100 | 3xx: 0 | 4xx: 0 | 5xx: 0 | Unknown: 0
# ============================================================
# 100 requests for a /json resource served at localhost:8000
# 5 batches of 20 requests performed concurently
./blowhole -n 100 -c 5 -url "http://localhost:8000/json"
Uniqueness is guaranteed by adding an "id" header to each request with the following format:
"id: RIDxxx.UIDxxxxx.CIDxxxxxx"
Where:
RID
: run ID - same for each run. Increases for each run in a batch of runs (see batched runs). Starts withRID001
UID
: user ID - same for each "user" (the concurrency level corresponds to the number of goroutines sending a portion of the total requests).CID
: count ID - different with each request performed for a given user.
For example:
./blowhole -n 10 -c 2 -url http://localhost:8080/get
One run of 10 requests and 2 concurrent users sends 10 requests with the following 10 unique id
headers:
Header 1: "id: RID001.UID00000.CID000000"
Header 2: "id: RID001.UID00000.CID000001"
Header 3: "id: RID001.UID00000.CID000002"
Header 4: "id: RID001.UID00000.CID000003"
Header 5: "id: RID001.UID00000.CID000004"
Header 6: "id: RID001.UID00001.CID000000"
Header 7: "id: RID001.UID00001.CID000001"
Header 8: "id: RID001.UID00001.CID000002"
Header 9: "id: RID001.UID00001.CID000003"
Header 10: "id: RID001.UID00001.CID000004"
# 100 requests for a /json resource served at localhost:8000
# 5 batches of 20 requests performed concurently
# Each request contains a unique "id: RID012.UIDxxxxx.CIDxxxxxx" header
./blowhole -n 100 -c 5 -url "http://localhost:8000/json" -run 12
Results can be written to a local file using the -o
option.
# 100 requests for a /json resource served at localhost:8000
# 5 batches of 20 requests performed concurently
# Write results to a file named out.log
./blowhole -n 30000 -c 1000 -url "http://localhost:8000/json" -o "out.log"
# Results:
# ============================================================
# Test "unnamed" running - Run: RID001
#
#
# 100% |████████████████████████████████████████████████████████████| (30000/30000, 7493 requests/s) [4s]
#
# Error count:
# + 80: "the server closed connection before (...)"
# + 1: "timeout"
# ============================================================
# Contents of "out.log"
# 2023/12/28 15:17:26 test unnamed,RID001,30000,1000
# 2023/12/28 15:17:30 30000,7089,81
Two lines will be logged for each run, with comma-separated values in each line as follows:
Line 1: Start_timestamp test_name,run_id,n,c
Line 2: End_timestamp requests_sent,average_rps,failed_requests
Blowhole uses a client from the fasthttp library.
Currently, there are three parameters that can be adjusted for this client: maxconn
, wtimeout
, and rtimeout
# 100 requests for a /json resource served at localhost:8000
# Use up to 3 connections per host
# Wait for up to 2 seconds before a request timeout
# Wait for up to 1 second before a response timeout
./blowhole -n 100 -url "http://localhost:8000/json" -maxconn 3 -wtimeout 2000 -rtimeout 1000
Blowhole can perform the requests in distributed mode, for those times when you just need more cowbell.
In order to run blowhole in distributed mode, we need to specify the -distributed
option:
# 100 requests for a /json resource served at localhost:8000
# Perform requests using distributed clients
# Use instance as coordinator for distributed workers
./blowhole -n 100 -url "http://localhost:8000/json" -distributed
Now that we have a coordinator, we need workers. For this, we need to specify the -worker
flag in
addition to the -distributed
one when running blowhole from other machines:
# 100 requests for a /json resource served at localhost:8000
# Perform requests using distributed clients
# Use instance as a distributed worker
./blowhole -n 100 -url "http://localhost:8000/json" -distributed -worker
A collection of runs can be bundled as a test. All runs in a test can be specified in a YAML document as follows:
sample.yml
name: mytest
url: http://localhost:8080/json
runs:
- requests: 5
concurrency: 3
- requests: 900
concurrency: 10
- requests: 100
concurrency: 100
url: http://myurl/foo
- id: RID999
requests: 1000
concurrency: 10
A test named "mytest" is specified above, with 4 runs equivalent to the following commands:
./blowhole -n 5 -c 3 -url http://localhost:8080/json -run 1 ;
./blowhole -n 900 -c 10 -url http://localhost:8080/json -run 2 ;
./blowhole -n 100 -c 100 -url http://myurl/foo -run 3 ;
./blowhole -n 1000 -c 10 -url http://localhost:8080/json -run 999
Instead, all runs defined in the sample.yml
file can be performed in one go like so:
# Perform tests specified in "sample.yml" sequentially
./blowhole -f "sample.yml"
See the batch spec reference for more information about each field in the spec.
Each field in the run spec overrides any command-line option, except for those regarding the fasthttp client (maxconn
, wtimeout
, rtimeout
)
# Perform tests specified in "sample.yml" sequentially, ignoring value passed with -n option
# Wait for up to 100 milliseconds before a response timeout
./blowhole -f "sample.yml" -n 99 -rtimeout 100
If a field is not declared in the spec, it can be passed as a command-line option:
# Perform tests specified in "sample.yml" sequentially
# Write results to a file named out.log
./blowhole -f "sample.yml" -o "out.log"
-url: string Target URL to perform requests to (default "http://localhost:8000/")
-n: int Number of requests to perform (default 1)
-c: int Number of concurrent connections (default 1)
-run: int Run number to use as Run ID in "id" header (default 1)
-o: string Results are written to this path (default "stdout")
-distributed: bool Distributed clients are used when set to true (default false)
-worker: bool Run as a distributed worker when set to true (default false)
-maxconn: int Maximum number of connections per each host (default 1000)
-wtimeout: int Maximum duration to write full request in ms (default 500)
-rtimeout: int Maximum duration to read full response in ms (default 500)
-file: string Path of YAML file describing a batch of runs
// top-level fields for each test spec
name string Name of the test. If not specified, defaults to "unnamed"
url string Target URL. Required
output string Output file path. If not specified, results are written to stdout
distributed bool Distributed clients are used when set to true
worker bool Run as a distributed worker when set to true
runs []runConf Collection of runs
// field for each run (runConf)
requests int Number of requests to perform
concurrency int Number of concurrent connections
url string Target URL to perform requests to
id string String to replace `RIDxxx` substring in "id" header
© 2016-2024 Graylog, Inc.