Skip to content
A load tester focused on lifecycle issues and long-running tests
Go Dockerfile Shell
Branch: master
Clone or download
siggy Migrate repo to Go modules (#70)
This change migrates the repo from dep to Go modules. Changes include:
- replace Gopkg.toml and GoPkg.lock with go.mod and go.sum
- update Dockerfile to no longer rely on GOPATH
- remove vendor
- upgrade to circleci2

Relates to linkerd/linkerd2#1488

Signed-off-by: Andrew Seigner <siggy@buoyant.io>
Latest commit 23b1d0e Mar 1, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.circleci Migrate repo to Go modules (#70) Mar 2, 2019
hdrreport Introduce latency unit configurability (#65) Aug 10, 2018
marathon -url has been removed Nov 7, 2016
ring circle ci support Jan 26, 2017
window circle ci support Jan 26, 2017
.gitignore Migrate to vendor (#22) Oct 10, 2016
CHANGELOG.md Update CHANGELOG for 1.2.0 release (#66) Aug 10, 2018
CONTRIBUTING.md Adding a basic CONTRIBUTORS file to help guide PRs Jan 9, 2017
DCO Add DCO file Apr 18, 2018
Dockerfile Migrate repo to Go modules (#70) Mar 2, 2019
LICENSE Initial commit May 6, 2016
README.md Add -iterations to specify a budget for the experiment (#68) Nov 19, 2018
RELEASE.md prep for 1.1.0, docker hub release update Jan 26, 2017
go.mod Migrate repo to Go modules (#70) Mar 2, 2019
go.sum Migrate repo to Go modules (#70) Mar 2, 2019
hash_sample_test.go Optionally check request body against a hash. (#57) Mar 29, 2017
main.go Add -iterations to specify a budget for the experiment (#68) Nov 19, 2018
qps_test.go
release.sh Revert "Fix “case-insensitive import collision”" Mar 23, 2017

README.md

CircleCI

slow_cooker

A load tester for tenderizing your servers.

Most load testers work by sending as much traffic as possible to a backend. We wanted a different approach, we wanted to be able to test a service with a predictable load and concurrency level for a long period of time. Instead of getting a report at the end, we wanted periodic reports of qps and latency.

Running it

go build; ./slow_cooker <url>

or:

go run main.go <url>

Testing

go test ./...

Flags

Flag Default Description
-qps 1 QPS to send to backends per request thread.
-concurrency 1 Number of goroutines to run, each at the specified QPS level. Measure total QPS as qps * concurrency.
-iterations 0 Number of iterations for the experiment. Exits gracefully after iterations * interval (default 0, meaning infinite).
-compress <unset> If set, ask for compressed responses.
-data <none> Include the specified body data in requests. If the data starts with a '@' the remaining value will be treated as a file path to read the body data from, or if the data value is '@-', the body data will be read from stdin.
-hashSampleRate 0.0 Sampe Rate for checking request body's hash. Interval in the range of [0.0, 1.0]
-hashValue <none> fnv-1a hash value to check the request body against
-header <none> Adds additional headers to each request. Can be specified multiple times. Format is key: value.
-host <none> Overrides the default host header value that's set on each request.
-interval 10s How often to report stats to stdout.
-latencyUnit ms latency units [ms
-method GET Determines which HTTP method to use when making the request.
-metric-addr <none> Address to use when serving the Prometheus /metrics endpoint. No metrics are served if unset. Format is host:port or :port.
-noLatencySummary <unset> If set, don't print the latency histogram report at the end.
-noreuse <unset> If set, do not reuse connections. Default is to reuse connections.
-reportLatenciesCSV <none> Filename to write CSV latency values. Format of CSV is millisecond buckets with number of requests in each bucket.
-timeout 10s Individual request timeout.
-totalRequests <none> Exit after sending this many requests.
-help <unset> If set, print all available flags and exit.

Using a URL file

If the <url> argument begins with @ the argument will be treated as a file path to read a newline separated list of URLs to send requests to, or if the value is @-, the url list will be read from stdin.

Example url file contents:

http://localhost:4140/foo
http://localhost:4140/bar
http://localhost:4140/baz

Reading url list from a file:

$ slow_cooker -qps 100 @urllist

Using a hypothetical url generation script to pipe url list to slow cooker via stdin:

$ url_generator | slow_cooker -qps 100 @-

The urls in the list file will be processed sequentially.

Using multiple Host headers

If you want to send multiple Host headers to a backend, pass a comma separated list to the host flag. Each request will be selected randomly from the list.

For more complex distributions, you can run multiple slow_cooker processes:

$ slow_cooker -host web_a,web_b -qps 200 http://localhost:4140

$ slow_cooker -host web_b -qps 100 http://localhost:4140

This example will send 300 qps total to http://localhost:4140/ with 100 qps sent with Host: web_a and 200 qps sent with Host: web_b

TLS use

Pass in an https url and it'll use TLS automatically.

Warning We do not verify the certificate, we use InsecureSkipVerify: true

Example usage

$ ./slow_cooker -qps 100 -concurrency 10 http://slow_server

2016-05-16T20:45:05Z 0   7102/0/0 10000 71% 10s 0 [ 12  26  37  91 ] 91
2016-05-16T20:45:16Z 1   7120/0/0 10000 71% 10s 1 [ 11  27  37  53 ] 53
2016-05-16T20:45:26Z 2   7158/0/0 10000 71% 10s 0 [ 11  27  37  74 ] 74
2016-05-16T20:45:36Z 3   7169/0/0 10000 71% 10s 1 [ 11  27  36  52 ] 52
2016-05-16T20:45:46Z 4   7273/0/0 10000 72% 10s 0 [ 11  27  36  58 ] 58
2016-05-16T20:45:56Z 5   7087/0/0 10000 70% 10s 1 [ 11  28  37  61 ] 61
2016-05-16T20:46:07Z 6   7231/0/0 10000 72% 10s 0 [ 11  26  35  71 ] 71
2016-05-16T20:46:17Z 7   7257/0/0 10000 72% 10s 0 [ 11  27  36  57 ] 57
2016-05-16T20:46:27Z 8   7205/0/0 10000 72% 10s 0 [ 11  27  36  64 ] 64
2016-05-16T20:46:37Z 9   7256/0/0 10000 72% 10s 0 [ 11  27  36  62 ] 62
2016-05-16T20:46:47Z 10  7164/0/0 10000 71% 10s 0 [ 11  27  38  74 ] 74
2016-05-16T20:46:58Z 11  7232/0/0 10000 72% 10s 0 [ 11  26  35  63 ] 63

In this example, we see that the server is too slow to keep up with our requested load. that slowness is noted via the throughput percentage.

Docker usage

Run

docker run -it buoyantio/slow_cooker -qps 100 -concurrency 10 http://$(docker-machine ip default):4140

Build your own

docker build -t buoyantio/slow_cooker -f Dockerfile .

Log format

We use vertical alignment in the output to help find anomalies and spot slowdowns. If you're running multi-hour tests, bumping up the reporting interval to 60 seconds (60s or 1m) is recommended.

$timestamp $good/$bad/$failed $trafficGoal $percentGoal $interval $min [$p50 $p95 $p99 $p999] $max $bhash

bad means a status code in the 500 range. failed means a connection failure. percentGoal is calculated as the total number of good and bad requests as a percentage of trafficGoal.

bhash is the number of failed hashes of body content. A value greater than 0 indicates a real problem.

Tips and tricks

keep a logfile

Use tee to keep a logfile of slow_cooker results and cut to find bad or failed requests.

./slow_cooker_linux_amd64 -qps 5 -concurrency 20 -interval 10s http://localhost:4140 | tee slow_cooker.log

use cut to look at specific fields from your tee'd logfile

cat slow_cook.log |cut -d ' ' -f 3 | cut -d '/' -f 2 |sort -rn |uniq -c

will show all bad (status code >= 500) requests.

cat slow_cook.log |cut -d ' ' -f 3 | cut -d '/' -f 3 |sort -rn |uniq -c

will show all failed (connection refused, dropped, etc) requests.

dig into the full latency report

With the -reportLatenciesCSV flag, you can thoroughly inspect your service's latency instead of relying on pre-computed statistical summaries. We chose CSV to allow for easy integration with statistical environments like R and standard spreadsheet tools like Excel.

use the latency CSV output to see system performance changes

Use -totalRequests and -reportLatenciesCSV to see how your system latency grows as a function of traffic levels.

use -concurrency to improve throughput

If you're not hitting the throughput numbers you expect, try increasing -concurrency so your requests are issued over more goroutines. Each goroutine issues requests serially, waiting for a response before issuing the next request.

If you have scripts that process slow_cooker logs, feel free to add them to this project!

You can’t perform that action at this time.