HTTP load testing tool with implementations in Go, Rust, Zig, and Python. This repository explores different approaches to building high-performance load testers, providing tools to benchmark web services and compare language/runtime characteristics for this type of workload. Key metrics like RPS, success/failure counts, and response latencies are tracked.
This repository contains separate implementations of the load tester in the following languages:
- Go: See the
go/directory. - Rust: See the
rust/directory. - Zig: See the
zig/directory. - Python: See the
python/directory. - TypeScript/Node.js: See the
typescript/directory. - Elixir: See the
elixir/directory. - Perl: See the
perl/directory. - Bash: See the
bash/directory.
While specific features might vary slightly between implementations, the general goals include:
- Configurable number of concurrent threads/workers.
- Configurable number of requests per thread.
- Customizable target URL.
- Support for authentication tokens (e.g., Bearer token).
- Collection and display of performance metrics.
- Payload for POST requests (e.g., from
payload.json).
The load testers aim to collect and report the following metrics:
- Total Test Duration: Overall time taken for the test to complete.
- Total Requests: The total number of requests made.
- Successful Requests: Count of requests that completed successfully (e.g., HTTP 200 OK, 201 Created).
- Failed Requests: Count of requests that failed.
- Requests Per Second (RPS): The rate at which requests were processed.
- Response Time Statistics (ms):
- Minimum response time.
- Average response time.
- Maximum response time.
load-tester/
βββ go/ # Go implementation
β βββ main.go
β βββ payload.json (expected in go/)
βββ rust/ # Rust implementation
β βββ src/
β β βββ main.rs
β βββ payload.json (expected in rust/)
βββ zig/ # Zig implementation
β βββ src/
β β βββ main.zig
β β βββ payload.json (expected in zig/src/)
β βββ .env (expected in zig/)
βββ python/ # Python implementation
β βββ main.py
β βββ requirements.txt
β βββ payload.json (expected in python/)
β βββ .env (expected in python/)
βββ typescript/ # TypeScript/Node.js implementation
βββ src/
β βββ main.ts
βββ package.json
βββ tsconfig.json
βββ payload.json (expected in typescript/)
βββ .env (expected in typescript/)
βββ elixir/ # Elixir implementation
β βββ mix.exs
β βββ lib/
β β βββ load_tester.ex
β β βββ load_tester/
β β βββ worker.ex
β βββ payload.json (expected in elixir/)
β βββ .env_example (example for .env in elixir/)
β βββ .env (expected in elixir/)
βββ perl/ # Perl implementation
β βββ main.pl
β βββ payload.json (expected in perl/)
β βββ .env (expected in perl/)
βββ bash/ # Bash implementation
β βββ load_test.sh
β βββ payload.json (expected in bash/)
β βββ .env (expected in bash/)
The Zig version utilizes std.http.Client for making HTTP requests and dotenv.zig for managing configuration through a .env file. The JSON payload is embedded into the executable at compile time.
- Zig compiler (e.g., version 0.14.1 or later). You can download it from ziglang.org.
-
Create a
.envfile in thezig/directory with the following variables:# Number of concurrent threads to use NUM_THREADS=20 # Number of requests each thread will make REQUESTS_PER_THREAD=50 # Target URL for the load test TARGET_URL="http://localhost:3000/api/foo" # (Optional) Authentication token (Bearer token) AUTH_TOKEN=""
-
Ensure a
payload.jsonfile is present in thezig/src/directory. This file contains the JSON body for POST requests and will be embedded by the compiler.
Navigate to the zig/ directory and run:
zig build runThis command will compile (embedding zig/src/payload.json) and run the load tester. Ensure the .env file is configured in zig/.
info: π Starting load test (Zig v0.14+ with std.http.Client & dotenv.zig)...
info: Threads: 20, Requests/Thread: 50, Total: 1000
info: Target URL: http://localhost:3000/api/foo
info: Auth Token: Not set
info: ----------------------------------------------------------------------
... (individual request logs) ...
info: ----------------------------------------------------------------------
info: β
Test completed in 12675.31 ms
info: Total requests: 1000
info: -> Successes β
: 1000
info: -> Failures β: 0
info: Performance: ~78.90 requests/second (RPS)
info: Response times (ms): min 190.21 | avg 249.48 | max 870.09
The Go version uses the standard net/http package and github.com/joho/godotenv for configuration.
- Go (e.g., version 1.18 or newer).
-
Create a
.envfile in thego/directory with the following variables (or set them as environment variables):# Number of concurrent threads to use NUM_THREADS=20 # Number of requests each thread will make REQUESTS_PER_THREAD=50 # Target URL for the load test TARGET_URL="http://localhost:3000/api/foo" # (Optional) Authentication token (Bearer token) AUTH_TOKEN=""
-
Ensure a
payload.jsonfile is present in thego/directory.
Navigate to the go/ directory and run:
# Build the executable
go build -o go_load_tester main.go
# Run the load tester
./go_load_testerEnsure the .env file (if used) and payload.json are in the go/ directory when running.
The Rust version uses the reqwest crate for HTTP requests and the dotenv crate for configuration.
- Rust (e.g., latest stable version).
- Cargo (Rust's package manager).
-
Create a
.envfile in therust/directory with the following variables (or set them as environment variables):# Number of concurrent threads to use NUM_THREADS=20 # Number of requests each thread will make REQUESTS_PER_THREAD=50 # Target URL for the load test TARGET_URL="http://localhost:3000/api/foo" # (Optional) Authentication token (Bearer token) AUTH_TOKEN=""
-
Ensure a
payload.jsonfile is present in therust/directory.
Navigate to the rust/ directory and run:
# Build the executable (optimized release build)
cargo build --release
# Run the load tester
./target/release/rust_load_testerEnsure the .env file (if used) and payload.json are in the rust/ directory when running the compiled executable.
The Python version uses the requests library for HTTP calls, python-dotenv for configuration, and threading for concurrency.
- Python (e.g., version 3.8 or newer recommended).
pip(Python package installer).
-
Create a
.envfile in thepython/directory with the following variables (or set them as environment variables):# Number of concurrent threads to use NUM_THREADS=20 # Number of requests each thread will make REQUESTS_PER_THREAD=50 # Target URL for the load test TARGET_URL="http://localhost:3000/api/foo" # (Optional) Authentication token (Bearer token) AUTH_TOKEN=""
-
Ensure a
payload.jsonfile is present in thepython/directory.
Navigate to the python/ directory and run:
# Install dependencies
pip install -r requirements.txt
# Run the load tester
python main.pyEnsure the .env file (if used) and payload.json are in the python/ directory when running.
YYYY-MM-DD HH:MM:SS INFO π Starting load test (Python)...
YYYY-MM-DD HH:MM:SS INFO Threads: 20, Requests/Thread: 50, Total: 1000
YYYY-MM-DD HH:MM:SS INFO Target URL: http://localhost:3000/api/foo
YYYY-MM-DD HH:MM:SS INFO Auth Token: Not set
----------------------------------------------------------------------
... (individual request logs) ...
----------------------------------------------------------------------
YYYY-MM-DD HH:MM:SS INFO β
Test completed in 12345.67 ms
YYYY-MM-DD HH:MM:SS INFO Total requests processed: 1000
YYYY-MM-DD HH:MM:SS INFO -> Successes β
: 1000
YYYY-MM-DD HH:MM:SS INFO -> Failures β: 0
YYYY-MM-DD HH:MM:SS INFO Performance: ~81.00 requests/second (RPS)
YYYY-MM-DD HH:MM:SS INFO Response times (ms): min 100.00 | avg 120.00 | max 250.00
The TypeScript/Node.js version uses axios for HTTP requests, dotenv for configuration, and Node.js worker_threads for concurrency. It requires compilation from TypeScript to JavaScript before running.
- Node.js (e.g., LTS version, v18.x or v20.x or newer recommended).
pnpm(Performant npm). You can install it following the instructions at pnpm.io.
-
Create a
.envfile in thetypescript/directory with the following variables:# Number of concurrent worker threads to use NUM_THREADS=20 # Number of requests each thread will make REQUESTS_PER_THREAD=50 # Target URL for the load test TARGET_URL="http://localhost:3000/api/foo" # (Optional) Authentication token (Bearer token) AUTH_TOKEN=""
-
Ensure a
payload.jsonfile is present in thetypescript/directory. This file contains the JSON body for POST requests.
Navigate to the typescript/ directory and run:
# Install dependencies (run this once initially)
pnpm install
# Compile TypeScript to JavaScript (creates a dist/ directory)
pnpm run build
# Run the load tester (executes the compiled JavaScript in dist/)
pnpm start
# Alternatively, to run directly using ts-node (for development, skips build step)
# pnpm run devEnsure the .env file and payload.json are in the typescript/ directory when running.
π Starting load test (TypeScript/Node.js)...
Threads: 20, Requests/Thread: 50, Total: 1000
Target URL: http://localhost:3000/api/foo
Auth Token: Not set
----------------------------------------------------------------------
Thread 1 | Request 1/50 | Status: 200
Thread 2 | Request 1/50 | Status: 200
... (more individual request logs) ...
Thread 20 | Request 50/50 | Status: 200
----------------------------------------------------------------------
β
Test completed in 1350.78 ms
Total requests processed: 1000
-> Successes β
: 1000
-> Failures β: 0
Performance: ~740.31 requests/second (RPS)
Response times (ms): min 5.21 | avg 12.87 | max 45.03
The Elixir version uses the HTTPoison library for HTTP requests and Dotenv for configuration. It leverages Elixir's concurrency model with GenServer for worker management.
- Elixir (e.g., version 1.12 or newer). You can find installation instructions on elixir-lang.org.
- Mix (Elixir's build tool, comes with Elixir).
-
Navigate to the
elixir/directory. -
Copy
.env_exampleto.env(i.e.,cp .env_example .env). -
Edit the
.envfile with your desired configuration:TARGET_URL=http://localhost:8080/test REQUESTS_PER_USER=100 CONCURRENT_USERS=10 # PAYLOAD_PATH=payload.json # Optional, defaults to payload.json in the elixir/ directory
-
Ensure a
payload.jsonfile is present in theelixir/directory. This file contains the JSON body for POST requests. An example is provided.
Navigate to the elixir/ directory and run the following commands:
# Fetch dependencies
mix deps.get
# Compile the project (optional, mix run will compile if needed)
mix compile
# Run the load tester as an escript
# This will compile and create a self-contained executable script.
# The .env file needs to be in the directory where you run the escript,
# or you can set environment variables directly.
mix escript.build
./load_tester
# OR, to run directly with mix (slower startup, but good for development):
# mix run -e "LoadTester.main([])"Ensure the .env file (if used) and payload.json are in the elixir/ directory when running.
info: Starting load test with 10 concurrent users, 100 requests each.
info: Target URL: http://localhost:8080/test
# ... (potential worker logs if enabled, or other info messages) ...
info: ---- Load Test Results ----
info: Total requests: 1000
info: Successful requests: 1000
info: Failed requests: 0
info: Total duration: 5.23s
info: Requests per second (RPS): 191.20
info: Average request duration (from workers): 45.12ms
The Perl version prioritizes portability and can run on a default Perl installation. If the optional Furl module is available it will be used for higher throughput; otherwise it falls back to LWP::UserAgent.
- Perl 5.32 or newer (threads enabled in the build).
- Recommended CPAN modules:
Try::Tiny(small dependency, used to detect Furl).Furl(optional but faster).LWP::UserAgent(already in many Perl distributions).
Install them with cpanm Try::Tiny Furl or your preferred CPAN client.
-
Create a
.envfile in theperl/directory with the following variables (or set them as environment variables):# Number of concurrent threads to use NUM_THREADS=20 # Number of requests each thread will make REQUESTS_PER_THREAD=50 # Target URL for the load test TARGET_URL="http://localhost:3000/api/foo" # (Optional) Authentication token (Bearer token) AUTH_TOKEN=""
-
Ensure a
payload.jsonfile is present in theperl/directory. This file contains the JSON body for POST requests.
Navigate to the perl/ directory and run:
# Execute directly with Perl
perl main.pl
# If you want the best performance, be sure Furl is installed:
cpanm Furl # once, optional but recommended
perl main.plEnsure the .env file (if used) and payload.json are in the perl/ directory when running.
π Starting load test (Perl)...
Threads: 20, Requests/Thread: 50, Total: 1000
Target URL: http://localhost:3000/api/foo
Auth Token: Not set
----------------------------------------------------------------------
Thread 1 | Request 1/50 | Status: 200
Thread 2 | Request 1/50 | Status: 200
... (more individual request logs) ...
Thread 20 | Request 50/50 | Status: 200
----------------------------------------------------------------------
β
Test completed in 2175.42 ms
Total requests: 1000
-> Successes β
: 1000
-> Failures β: 0
Performance: ~459.76 requests/second (RPS)
Response times (ms): min 6.45 | avg 27.12 | max 73.81
La versione Bash Γ¨ pensata per la massima portabilitΓ : richiede solo bash, curl e gli strumenti POSIX standard (awk, date, mktemp). Ogni thread viene eseguito come subshell in background, con metriche aggregate a fine test.
- Unix-like shell con
bash4.x o superiore. curl,awk,datecon supporto nanosecondi (date +%s%N).
-
Creare (facoltativo) un file
.envnella directorybash/con le variabili:NUM_THREADS=20 REQUESTS_PER_THREAD=50 TARGET_URL="http://localhost:3000/api/foo" AUTH_TOKEN="" PAYLOAD_FILE=payload.json
-
Aggiungere
payload.jsonnella stessa directory se si desidera inviare un corpo JSON; se assente, verrΓ inviata una richiesta vuota.
cd bash
chmod +x load_test.sh # solo la prima volta
./load_test.shπ Starting load test (Bash)...
Threads: 20, Requests/Thread: 50, Total: 1000
Target URL: http://localhost:3000/api/foo
Auth Token: Not set
----------------------------------------------------------------------
Thread 1 | Request 1/50 | Status: 200
Thread 2 | Request 1/50 | Status: 200
... (altri log) ...
Thread 20 | Request 50/50 | Status: 200
----------------------------------------------------------------------
β
Test completed in 4230.11 ms
Total requests: 1000
-> Successes β
: 1000
-> Failures β: 0
Performance: ~236.44 requests/second (RPS)
Response times (ms): min 8.57 | avg 39.82 | max 110.24
Contributions are welcome! Please feel free to submit a pull request or open an issue.
(Consider adding a license file, e.g., MIT, Apache 2.0. If so, mention it here.)