README.md
1# Vegeta [![Build Status](https://github.com/tsenart/vegeta/workflows/CI/badge.svg)](https://github.com/tsenart/vegeta/actions) [![Go Report Card](https://goreportcard.com/badge/github.com/tsenart/vegeta)](https://goreportcard.com/report/github.com/tsenart/vegeta) [![GoDoc](https://godoc.org/github.com/tsenart/vegeta?status.svg)](https://godoc.org/github.com/tsenart/vegeta) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/tsenart/vegeta?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Donate](https://img.shields.io/badge/donate-bitcoin-yellow.svg)](#donate)
2
3Vegeta is a versatile HTTP load testing tool built out of a need to drill
4HTTP services with a constant request rate.
5It can be used both as a command line utility and a library.
6
7![Vegeta](http://fc09.deviantart.net/fs49/i/2009/198/c/c/ssj2_vegeta_by_trunks24.jpg)
8
9## Install
10
11### Pre-compiled executables
12
13Get them [here](http://github.com/tsenart/vegeta/releases).
14
15### Homebrew on Mac OS X
16
17You can install Vegeta using the [Homebrew](https://github.com/Homebrew/homebrew/) package manager on Mac OS X:
18
19```shell
20$ brew update && brew install vegeta
21```
22
23### Source
24
25You need `go` installed and `GOBIN` in your `PATH`. Once that is done, run the
26command:
27
28```shell
29$ go get -u github.com/tsenart/vegeta
30```
31
32## Versioning
33
34Both the library and the CLI are versioned with [SemVer v2.0.0](https://semver.org/spec/v2.0.0.html).
35
36After [v8.0.0](https://github.com/tsenart/vegeta/tree/v8.0.0), the two components
37are versioned separately to better isolate breaking changes to each.
38
39CLI releases are tagged with `cli/vMAJOR.MINOR.PATCH` and published on the [Github releases page](https://github.com/tsenart/vegeta/releases).
40As for the library, new versions are tagged with both `lib/vMAJOR.MINOR.PATCH` and `vMAJOR.MINOR.PATCH`.
41The latter tag is required for compatibility with `go mod`.
42
43## Contributing
44
45See [CONTRIBUTING.md](.github/CONTRIBUTING.md).
46
47## Usage manual
48
49```console
50Usage: vegeta [global flags] <command> [command flags]
51
52global flags:
53 -cpus int
54 Number of CPUs to use (defaults to the number of CPUs you have)
55 -profile string
56 Enable profiling of [cpu, heap]
57 -version
58 Print version and exit
59
60attack command:
61 -body string
62 Requests body file
63 -cert string
64 TLS client PEM encoded certificate file
65 -chunked
66 Send body with chunked transfer encoding
67 -connections int
68 Max open idle connections per target host (default 10000)
69 -duration duration
70 Duration of the test [0 = forever]
71 -format string
72 Targets format [http, json] (default "http")
73 -h2c
74 Send HTTP/2 requests without TLS encryption
75 -header value
76 Request header
77 -http2
78 Send HTTP/2 requests when supported by the server (default true)
79 -insecure
80 Ignore invalid server TLS certificates
81 -keepalive
82 Use persistent connections (default true)
83 -key string
84 TLS client PEM encoded private key file
85 -laddr value
86 Local IP address (default 0.0.0.0)
87 -lazy
88 Read targets lazily
89 -max-body value
90 Maximum number of bytes to capture from response bodies. [-1 = no limit] (default -1)
91 -max-workers uint
92 Maximum number of workers (default 18446744073709551615)
93 -name string
94 Attack name
95 -output string
96 Output file (default "stdout")
97 -proxy-header value
98 Proxy CONNECT header
99 -rate value
100 Number of requests per time unit [0 = infinity] (default 50/1s)
101 -redirects int
102 Number of redirects to follow. -1 will not follow but marks as success (default 10)
103 -resolvers value
104 List of addresses (ip:port) to use for DNS resolution. Disables use of local system DNS. (comma separated list)
105 -root-certs value
106 TLS root certificate files (comma separated list)
107 -targets string
108 Targets file (default "stdin")
109 -timeout duration
110 Requests timeout (default 30s)
111 -unix-socket string
112 Connect over a unix socket. This overrides the host address in target URLs
113 -workers uint
114 Initial number of workers (default 10)
115
116encode command:
117 -output string
118 Output file (default "stdout")
119 -to string
120 Output encoding [csv, gob, json] (default "json")
121
122plot command:
123 -output string
124 Output file (default "stdout")
125 -threshold int
126 Threshold of data points above which series are downsampled. (default 4000)
127 -title string
128 Title and header of the resulting HTML page (default "Vegeta Plot")
129
130report command:
131 -buckets string
132 Histogram buckets, e.g.: "[0,1ms,10ms]"
133 -every duration
134 Report interval
135 -output string
136 Output file (default "stdout")
137 -type string
138 Report type to generate [text, json, hist[buckets], hdrplot] (default "text")
139
140examples:
141 echo "GET http://localhost/" | vegeta attack -duration=5s | tee results.bin | vegeta report
142 vegeta report -type=json results.bin > metrics.json
143 cat results.bin | vegeta plot > plot.html
144 cat results.bin | vegeta report -type="hist[0,100ms,200ms,300ms]"
145```
146
147#### `-cpus`
148
149Specifies the number of CPUs to be used internally.
150It defaults to the amount of CPUs available in the system.
151
152#### `-profile`
153
154Specifies which profiler to enable during execution. Both _cpu_ and
155_heap_ profiles are supported. It defaults to none.
156
157#### `-version`
158
159Prints the version and exits.
160
161### `attack` command
162
163#### `-body`
164
165Specifies the file whose content will be set as the body of every
166request unless overridden per attack target, see `-targets`.
167
168#### `-cert`
169
170Specifies the PEM encoded TLS client certificate file to be used with HTTPS requests.
171If `-key` isn't specified, it will be set to the value of this flag.
172
173#### `-chunked`
174
175Specifies whether to send request bodies with the chunked transfer encoding.
176
177#### `-connections`
178
179Specifies the maximum number of idle open connections per target host.
180
181#### `-duration`
182
183Specifies the amount of time to issue request to the targets.
184The internal concurrency structure's setup has this value as a variable.
185The actual run time of the test can be longer than specified due to the
186responses delay. Use 0 for an infinite attack.
187
188#### `-format`
189
190Specifies the targets format to decode.
191
192##### `json` format
193
194The JSON format makes integration with programs that produce targets dynamically easier.
195Each target is one JSON object in its own line. The method and url fields are required.
196If present, the body field must be base64 encoded. The generated [JSON Schema](lib/target.schema.json)
197defines the format in detail.
198
199```bash
200jq -ncM '{method: "GET", url: "http://goku", body: "Punch!" | @base64, header: {"Content-Type": ["text/plain"]}}' |
201 vegeta attack -format=json -rate=100 | vegeta encode
202```
203
204##### `http` format
205
206The http format almost resembles the plain-text HTTP message format defined in
207[RFC 2616](https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html) but it
208doesn't support in-line HTTP bodies, only references to files that are loaded and used
209as request bodies (as exemplified below).
210
211Although targets in this format can be produced by other programs, it was originally
212meant to be used by people writing targets by hand for simple use cases.
213
214Here are a few examples of valid targets files in the http format:
215
216###### Simple targets
217
218```
219GET http://goku:9090/path/to/dragon?item=ball
220GET http://user:password@goku:9090/path/to
221HEAD http://goku:9090/path/to/success
222```
223
224###### Targets with custom headers
225
226```
227GET http://user:password@goku:9090/path/to
228X-Account-ID: 8675309
229
230DELETE http://goku:9090/path/to/remove
231Confirmation-Token: 90215
232Authorization: Token DEADBEEF
233```
234
235###### Targets with custom bodies
236
237```
238POST http://goku:9090/things
239@/path/to/newthing.json
240
241PATCH http://goku:9090/thing/71988591
242@/path/to/thing-71988591.json
243```
244
245###### Targets with custom bodies and headers
246
247```
248POST http://goku:9090/things
249X-Account-ID: 99
250@/path/to/newthing.json
251```
252
253###### Add comments
254
255Lines starting with `#` are ignored.
256
257```
258# get a dragon ball
259GET http://goku:9090/path/to/dragon?item=ball
260# specify a test accout
261X-Account-ID: 99
262```
263
264#### `-h2c`
265
266Specifies that HTTP2 requests are to be sent over TCP without TLS encryption.
267
268#### `-header`
269
270Specifies a request header to be used in all targets defined, see `-targets`.
271You can specify as many as needed by repeating the flag.
272
273#### `-http2`
274
275Specifies whether to enable HTTP/2 requests to servers which support it.
276
277#### `-insecure`
278
279Specifies whether to ignore invalid server TLS certificates.
280
281#### `-keepalive`
282
283Specifies whether to reuse TCP connections between HTTP requests.
284
285#### `-key`
286
287Specifies the PEM encoded TLS client certificate private key file to be
288used with HTTPS requests.
289
290#### `-laddr`
291
292Specifies the local IP address to be used.
293
294#### `-lazy`
295
296Specifies whether to read the input targets lazily instead of eagerly.
297This allows streaming targets into the attack command and reduces memory
298footprint.
299The trade-off is one of added latency in each hit against the targets.
300
301#### `-max-body`
302
303Specifies the maximum number of bytes to capture from the body of each
304response. Remaining unread bytes will be fully read but discarded.
305Set to -1 for no limit. It knows how to intepret values like these:
306
307- `"10 MB"` -> `10MB`
308- `"10240 g"` -> `10TB`
309- `"2000"` -> `2000B`
310- `"1tB"` -> `1TB`
311- `"5 peta"` -> `5PB`
312- `"28 kilobytes"` -> `28KB`
313- `"1 gigabyte"` -> `1GB`
314
315#### `-name`
316
317Specifies the name of the attack to be recorded in responses.
318
319#### `-output`
320
321Specifies the output file to which the binary results will be written
322to. Made to be piped to the report command input. Defaults to stdout.
323
324#### `-rate`
325
326Specifies the request rate per time unit to issue against
327the targets. The actual request rate can vary slightly due to things like
328garbage collection, but overall it should stay very close to the specified.
329If no time unit is provided, 1s is used.
330
331A `-rate` of `0` or `infinity` means vegeta will send requests as fast as possible.
332Use together with `-max-workers` to model a fixed set of concurrent users sending
333requests serially (i.e. waiting for a response before sending the next request).
334
335Setting `-max-workers` to a very high number while setting `-rate=0` can result in
336vegeta consuming too many resources and crashing. Use with care.
337
338#### `-redirects`
339
340Specifies the max number of redirects followed on each request. The
341default is 10. When the value is -1, redirects are not followed but
342the response is marked as successful.
343
344#### `-resolvers`
345
346Specifies custom DNS resolver addresses to use for name resolution instead of
347the ones configured by the operating system. Works only on non Windows systems.
348
349#### `-root-certs`
350
351Specifies the trusted TLS root CAs certificate files as a comma separated
352list. If unspecified, the default system CAs certificates will be used.
353
354#### `-targets`
355
356Specifies the file from which to read targets, defaulting to stdin.
357See the [`-format`](#-format) section to learn about the different target formats.
358
359#### `-timeout`
360
361Specifies the timeout for each request. The default is 0 which disables
362timeouts.
363
364#### `-workers`
365
366Specifies the initial number of workers used in the attack. The actual
367number of workers will increase if necessary in order to sustain the
368requested rate, unless it'd go beyond `-max-workers`.
369
370#### `-max-workers`
371
372Specifies the maximum number of workers used in the attack. It can be used to
373control the concurrency level used by an attack.
374
375### `report` command
376
377```console
378Usage: vegeta report [options] [<file>...]
379
380Outputs a report of attack results.
381
382Arguments:
383 <file> A file with vegeta attack results encoded with one of
384 the supported encodings (gob | json | csv) [default: stdin]
385
386Options:
387 --type Which report type to generate (text | json | hist[buckets] | hdrplot).
388 [default: text]
389
390 --buckets Histogram buckets, e.g.: '[0,1ms,10ms]'
391
392 --every Write the report to --output at every given interval (e.g 100ms)
393 The default of 0 means the report will only be written after
394 all results have been processed. [default: 0]
395
396 --output Output file [default: stdout]
397
398Examples:
399 echo "GET http://:80" | vegeta attack -rate=10/s > results.gob
400 echo "GET http://:80" | vegeta attack -rate=100/s | vegeta encode > results.json
401 vegeta report results.*
402```
403
404#### `report -type=text`
405
406```console
407Requests [total, rate, throughput] 1200, 120.00, 65.87
408Duration [total, attack, wait] 10.094965987s, 9.949883921s, 145.082066ms
409Latencies [min, mean, 50, 95, 99, max] 90.438129ms, 113.172398ms, 108.272568ms, 140.18235ms, 247.771566ms, 264.815246ms
410Bytes In [total, mean] 3714690, 3095.57
411Bytes Out [total, mean] 0, 0.00
412Success [ratio] 55.42%
413Status Codes [code:count] 0:535 200:665
414Error Set:
415Get http://localhost:6060: dial tcp 127.0.0.1:6060: connection refused
416Get http://localhost:6060: read tcp 127.0.0.1:6060: connection reset by peer
417Get http://localhost:6060: dial tcp 127.0.0.1:6060: connection reset by peer
418Get http://localhost:6060: write tcp 127.0.0.1:6060: broken pipe
419Get http://localhost:6060: net/http: transport closed before response was received
420Get http://localhost:6060: http: can't write HTTP request on broken connection
421```
422
423The `Requests` row shows:
424
425- The `total` number of issued requests.
426- The real request `rate` sustained during the `attack` period.
427- The `throughput` of successful requests over the `total` period.
428
429The `Duration` row shows:
430
431- The `attack` time taken issuing all requests (`total` - `wait`)
432- The `wait` time waiting for the response to the last issued request (`total` - `attack`)
433- The `total` time taken in the attack (`attack` + `wait`)
434
435Latency is the amount of time taken for a response to a request to be read (including the `-max-body` bytes from the response body).
436
437- `min` is the minimum latency of all requests in an attack.
438- `mean` is the [arithmetic mean / average](https://en.wikipedia.org/wiki/Arithmetic_mean) of the latencies of all requests in an attack.
439- `50`, `90`, `95`, `99` are the 50th, 90th, 95th and 99th [percentiles](https://en.wikipedia.org/wiki/Percentile), respectively, of the latencies of all requests in an attack. To understand more about why these are useful, I recommend [this article](https://bravenewgeek.com/everything-you-know-about-latency-is-wrong/) from @tylertreat.
440- `max` is the maximum latency of all requests in an attack.
441
442The `Bytes In` and `Bytes Out` rows shows:
443
444- The `total` number of bytes sent (out) or received (in) with the request or response bodies.
445- The `mean` number of bytes sent (out) or received (in) with the request or response bodies.
446
447The `Success` ratio shows the percentage of requests whose responses didn't error and had status codes between **200** and **400** (non-inclusive).
448
449The `Status Codes` row shows a histogram of status codes. `0` status codes mean a request failed to be sent.
450
451The `Error Set` shows a unique set of errors returned by all issued requests. These include requests that got non-successful response status code.
452
453#### `report -type=json`
454
455All duration like fields are in nanoseconds.
456
457```json
458{
459 "latencies": {
460 "total": 237119463,
461 "mean": 2371194,
462 "50th": 2854306,
463 "90th": 3228223,
464 "95th": 3478629,
465 "99th": 3530000,
466 "max": 3660505,
467 "min": 1949582
468 },
469 "buckets": {
470 "0": 9952,
471 "1000000": 40,
472 "2000000": 6,
473 "3000000": 0,
474 "4000000": 0,
475 "5000000": 2
476 },
477 "bytes_in": {
478 "total": 606700,
479 "mean": 6067
480 },
481 "bytes_out": {
482 "total": 0,
483 "mean": 0
484 },
485 "earliest": "2015-09-19T14:45:50.645818631+02:00",
486 "latest": "2015-09-19T14:45:51.635818575+02:00",
487 "end": "2015-09-19T14:45:51.639325797+02:00",
488 "duration": 989999944,
489 "wait": 3507222,
490 "requests": 100,
491 "rate": 101.01010672380401,
492 "throughput": 101.00012489812,
493 "success": 1,
494 "status_codes": {
495 "200": 100
496 },
497 "errors": []
498}
499```
500
501In the `buckets` field, each key is a nanosecond value representing the lower bound of a bucket.
502The upper bound is implied by the next higher bucket.
503Upper bounds are non-inclusive.
504The highest bucket is the overflow bucket; it has no upper bound.
505The values are counts of how many requests fell into that particular bucket.
506If the `-buckets` parameter is not present, the `buckets` field is omitted.
507
508#### `report -type=hist`
509
510Computes and prints a text based histogram for the given buckets.
511Each bucket upper bound is non-inclusive.
512
513```console
514cat results.bin | vegeta report -type='hist[0,2ms,4ms,6ms]'
515Bucket # % Histogram
516[0, 2ms] 6007 32.65% ########################
517[2ms, 4ms] 5505 29.92% ######################
518[4ms, 6ms] 2117 11.51% ########
519[6ms, +Inf] 4771 25.93% ###################
520```
521
522#### `report -type=hdrplot`
523
524Writes out results in a format plottable by https://hdrhistogram.github.io/HdrHistogram/plotFiles.html.
525
526```
527Value(ms) Percentile TotalCount 1/(1-Percentile)
5280.076715 0.000000 0 1.000000
5290.439370 0.100000 200 1.111111
5300.480836 0.200000 400 1.250000
5310.495559 0.300000 599 1.428571
5320.505101 0.400000 799 1.666667
5330.513059 0.500000 999 2.000000
5340.516664 0.550000 1099 2.222222
5350.520455 0.600000 1199 2.500000
5360.525008 0.650000 1299 2.857143
5370.530174 0.700000 1399 3.333333
5380.534891 0.750000 1499 4.000000
5390.537572 0.775000 1548 4.444444
5400.540340 0.800000 1598 5.000000
5410.543763 0.825000 1648 5.714286
5420.547164 0.850000 1698 6.666667
5430.551432 0.875000 1748 8.000000
5440.553444 0.887500 1773 8.888889
5450.555774 0.900000 1798 10.000000
5460.558454 0.912500 1823 11.428571
5470.562123 0.925000 1848 13.333333
5480.565563 0.937500 1873 16.000000
5490.567831 0.943750 1886 17.777778
5500.570617 0.950000 1898 20.000000
5510.574522 0.956250 1911 22.857143
5520.579046 0.962500 1923 26.666667
5530.584426 0.968750 1936 32.000000
5540.586695 0.971875 1942 35.555556
5550.590451 0.975000 1948 40.000000
5560.597543 0.978125 1954 45.714286
5570.605637 0.981250 1961 53.333333
5580.613564 0.984375 1967 64.000000
5590.620393 0.985938 1970 71.113640
5600.629121 0.987500 1973 80.000000
5610.638060 0.989062 1976 91.424392
5620.648085 0.990625 1979 106.666667
5630.659689 0.992188 1982 128.008193
5640.665870 0.992969 1984 142.227279
5650.672985 0.993750 1986 160.000000
5660.680101 0.994531 1987 182.848784
5670.687810 0.995313 1989 213.356091
5680.695729 0.996094 1990 256.016385
5690.730641 0.996484 1991 284.414107
5700.785516 0.996875 1992 320.000000
5710.840392 0.997266 1993 365.764448
5721.009646 0.997656 1993 426.621160
5731.347020 0.998047 1994 512.032770
5741.515276 0.998242 1994 568.828214
5751.683532 0.998437 1995 639.795266
5761.887487 0.998633 1995 731.528895
5772.106249 0.998828 1996 853.242321
5782.325011 0.999023 1996 1023.541453
5792.434952 0.999121 1996 1137.656428
5802.544894 0.999219 1996 1280.409731
5812.589510 0.999316 1997 1461.988304
5822.605192 0.999414 1997 1706.484642
5832.620873 0.999512 1997 2049.180328
5842.628713 0.999561 1997 2277.904328
5852.636394 0.999609 1997 2557.544757
5862.644234 0.999658 1997 2923.976608
5872.652075 0.999707 1997 3412.969283
5882.658916 0.999756 1998 4098.360656
5892.658916 0.999780 1998 4545.454545
5902.658916 0.999805 1998 5128.205128
5912.658916 0.999829 1998 5847.953216
5922.658916 0.999854 1998 6849.315068
5932.658916 0.999878 1998 8196.721311
5942.658916 0.999890 1998 9090.909091
5952.658916 0.999902 1998 10204.081633
5962.658916 0.999915 1998 11764.705882
5972.658916 0.999927 1998 13698.630137
5982.658916 0.999939 1998 16393.442623
5992.658916 0.999945 1998 18181.818182
6002.658916 0.999951 1998 20408.163265
6012.658916 0.999957 1998 23255.813953
6022.658916 0.999963 1998 27027.027027
6032.658916 0.999969 1998 32258.064516
6042.658916 0.999973 1998 37037.037037
6052.658916 0.999976 1998 41666.666667
6062.658916 0.999979 1998 47619.047619
6072.658916 0.999982 1998 55555.555556
6082.658916 0.999985 1998 66666.666667
6092.658916 0.999986 1998 71428.571429
6102.658916 0.999988 1998 83333.333333
6112.658916 0.999989 1998 90909.090909
6122.658916 0.999991 1998 111111.111111
6132.658916 0.999992 1998 125000.000000
6142.658916 0.999993 1998 142857.142858
6152.658916 0.999994 1998 166666.666668
6162.658916 0.999995 1998 199999.999999
6172.658916 0.999996 1998 250000.000000
6182.658916 0.999997 1998 333333.333336
6192.658916 0.999998 1998 500000.000013
6202.658916 0.999999 1998 999999.999971
6212.658916 1.000000 1998 10000000.000000
622```
623
624### `encode` command
625
626```
627Usage: vegeta encode [options] [<file>...]
628
629Encodes vegeta attack results from one encoding to another.
630The supported encodings are Gob (binary), CSV and JSON.
631Each input file may have a different encoding which is detected
632automatically.
633
634The CSV encoder doesn't write a header. The columns written by it are:
635
636 1. Unix timestamp in nanoseconds since epoch
637 2. HTTP status code
638 3. Request latency in nanoseconds
639 4. Bytes out
640 5. Bytes in
641 6. Error
642 7. Base64 encoded response body
643 8. Attack name
644 9. Sequence number of request
645
646Arguments:
647 <file> A file with vegeta attack results encoded with one of
648 the supported encodings (gob | json | csv) [default: stdin]
649
650Options:
651 --to Output encoding (gob | json | csv) [default: json]
652 --output Output file [default: stdout]
653
654Examples:
655 echo "GET http://:80" | vegeta attack -rate=1/s > results.gob
656 cat results.gob | vegeta encode | jq -c 'del(.body)' | vegeta encode -to gob
657```
658
659### `plot` command
660
661![Plot](https://i.imgur.com/Jra1sNH.png)
662
663```
664Usage: vegeta plot [options] [<file>...]
665
666Outputs an HTML time series plot of request latencies over time.
667The X axis represents elapsed time in seconds from the beginning
668of the earliest attack in all input files. The Y axis represents
669request latency in milliseconds.
670
671Click and drag to select a region to zoom into. Double click to zoom out.
672Choose a different number on the bottom left corner input field
673to change the moving average window size (in data points).
674
675Arguments:
676 <file> A file output by running vegeta attack [default: stdin]
677
678Options:
679 --title Title and header of the resulting HTML page.
680 [default: Vegeta Plot]
681 --threshold Threshold of data points to downsample series to.
682 Series with less than --threshold number of data
683 points are not downsampled. [default: 4000]
684
685Examples:
686 echo "GET http://:80" | vegeta attack -name=50qps -rate=50 -duration=5s > results.50qps.bin
687 cat results.50qps.bin | vegeta plot > plot.50qps.html
688 echo "GET http://:80" | vegeta attack -name=100qps -rate=100 -duration=5s > results.100qps.bin
689 vegeta plot results.50qps.bin results.100qps.bin > plot.html
690```
691
692## Usage: Generated targets
693
694Apart from accepting a static list of targets, Vegeta can be used together with another program that generates them in a streaming fashion. Here's an example of that using the `jq` utility that generates targets with an incrementing id in their body.
695
696```console
697jq -ncM 'while(true; .+1) | {method: "POST", url: "http://:6060", body: {id: .} | @base64 }' | \
698 vegeta attack -rate=50/s -lazy -format=json -duration=30s | \
699 tee results.bin | \
700 vegeta report
701```
702
703## Usage: Distributed attacks
704
705Whenever your load test can't be conducted due to Vegeta hitting machine limits
706such as open files, memory, CPU or network bandwidth, it's a good idea to use Vegeta in a distributed manner.
707
708In a hypothetical scenario where the desired attack rate is 60k requests per second,
709let's assume we have 3 machines with `vegeta` installed.
710
711Make sure open file descriptor and process limits are set to a high number for your user **on each machine**
712using the `ulimit` command.
713
714We're ready to start the attack. All we need to do is to divide the intended rate by the number of machines,
715and use that number on each attack. Here we'll use [pdsh](https://code.google.com/p/pdsh/) for orchestration.
716
717```shell
718$ PDSH_RCMD_TYPE=ssh pdsh -b -w '10.0.1.1,10.0.2.1,10.0.3.1' \
719 'echo "GET http://target/" | vegeta attack -rate=20000 -duration=60s > result.bin'
720```
721
722After the previous command finishes, we can gather the result files to use on our report.
723
724```shell
725$ for machine in 10.0.1.1 10.0.2.1 10.0.3.1; do
726 scp $machine:~/result.bin $machine.bin &
727 done
728```
729
730The `report` command accepts multiple result files.
731It'll read and sort them by timestamp before generating reports.
732
733```console
734vegeta report *.bin
735```
736
737## Usage: Real-time Analysis
738
739If you are a happy user of iTerm, you can integrate vegeta with [jplot](https://github.com/rs/jplot) using [jaggr](https://github.com/rs/jaggr) to plot a vegeta report in real-time in the comfort of your terminal:
740
741```
742echo 'GET http://localhost:8080' | \
743 vegeta attack -rate 5000 -duration 10m | vegeta encode | \
744 jaggr @count=rps \
745 hist\[100,200,300,400,500\]:code \
746 p25,p50,p95:latency \
747 sum:bytes_in \
748 sum:bytes_out | \
749 jplot rps+code.hist.100+code.hist.200+code.hist.300+code.hist.400+code.hist.500 \
750 latency.p95+latency.p50+latency.p25 \
751 bytes_in.sum+bytes_out.sum
752```
753
754![](https://i.imgur.com/ttBDsQS.gif)
755
756## Usage (Library)
757
758The library versioning follows [SemVer v2.0.0](https://semver.org/spec/v2.0.0.html).
759Since [lib/v9.0.0](https://github.com/tsenart/vegeta/tree/lib/v9.0.0), the library and cli
760are versioned separately to better isolate breaking changes to each component.
761
762See [Versioning](#Versioning) for more details on git tag naming schemes and compatibility
763with `go mod`.
764
765```go
766package main
767
768import (
769 "fmt"
770 "time"
771
772 vegeta "github.com/tsenart/vegeta/v12/lib"
773)
774
775func main() {
776 rate := vegeta.Rate{Freq: 100, Per: time.Second}
777 duration := 4 * time.Second
778 targeter := vegeta.NewStaticTargeter(vegeta.Target{
779 Method: "GET",
780 URL: "http://localhost:9100/",
781 })
782 attacker := vegeta.NewAttacker()
783
784 var metrics vegeta.Metrics
785 for res := range attacker.Attack(targeter, rate, duration, "Big Bang!") {
786 metrics.Add(res)
787 }
788 metrics.Close()
789
790 fmt.Printf("99th percentile: %s\n", metrics.Latencies.P99)
791}
792```
793
794#### Limitations
795
796There will be an upper bound of the supported `rate` which varies on the
797machine being used.
798You could be CPU bound (unlikely), memory bound (more likely) or
799have system resource limits being reached which ought to be tuned for
800the process execution. The important limits for us are file descriptors
801and processes. On a UNIX system you can get and set the current
802soft-limit values for a user.
803
804```shell
805$ ulimit -n # file descriptors
8062560
807$ ulimit -u # processes / threads
808709
809```
810
811Just pass a new number as the argument to change it.
812
813## License
814
815See [LICENSE](LICENSE).
816
817## Donate
818
819If you use and love Vegeta, please consider sending some Satoshi to
820`1MDmKC51ve7Upxt75KoNM6x1qdXHFK6iW2`. In case you want to be mentioned as a
821sponsor, let me know!
822
823[![Donate Bitcoin](https://i.imgur.com/W9Vc51d.png)](#donate)
824