Fortio (Φορτίο) started as, and is, Istio's load testing tool and later (2018) graduated to be its own project.
Fortio runs at a specified query per second (qps) and records a histogram of execution time and calculates percentiles (e.g., p99 i.e., the response time such as 99% of the requests take less than that number (in seconds, SI unit)). It can run for a set duration, for a fixed number of calls, or until interrupted (at a constant target QPS, or max speed/load per connection/thread).
The name fortio comes from Greek φορτίο which means load/burden.
Fortio is a fast, small (less than 6Mb Docker image download, minimal dependencies), reusable, embeddable go library as well as a command line tool and server process, the server includes a simple web UI and REST API to trigger run and see graphical representation of the results (both a single latency graph and a multiple results comparative min, max, avg, qps and percentiles graphs).
Fortio also includes a set of server side features (similar to httpbin) to help debugging and testing: request echo back including headers, adding latency or error codes with a probability distribution, TCP echoing, TCP proxying, HTTP fan out/scatter and gather proxy server, gRPC echo/health in addition to HTTP, etc...
Fortio is quite mature and very stable with no known major bugs (lots of possible improvements if you want to contribute though!), and when bugs are found they are fixed quickly, so after 1 year of development and 42 incremental releases, we reached 1.0 in June 2018.
Fortio components can be used a library even for unrelated projects, for instance the stats, or fhttp utilities both client and server.
A recent addition is the new jrpc JSON Remote Procedure Calls library package (docs).
We also have moved some of the library to their own toplevel package, like: - Dynamic flags: fortio.org/dflag - Logger: fortio.org/log - now using structured JSON logs for servers (vs text for CLIs) since fortio 1.55 / log 1.4. In color since fortio 1.57 / log 1.6. - Version helper: fortio.org/version - CLI helpers integrating the above to reduce toil making new tools fortio.org/cli and servers fortio.org/scli for arguments, flags, usage, dynamic config, etc...
If you want to connect to fortio using HTTPS and fortio to provide real TLS certificates, or to multiplex gRPC and regular HTTP behind a single port, check out Fortio Proxy.
If you want fortio to generate detailed Open Telemetry traces use Fortiotel.
Fortio now embeds the grol scripting language, available using fortio script.
We publish a multi architecture Docker image (linux/amd64, linux/arm64, linux/ppc64le, linux/s390x) fortio/fortio.
For instance:
docker run -p 8080:8080 -p 8079:8079 fortio/fortio server & # For the server
docker run fortio/fortio load -logger-force-color http://www.google.com/ # For a test run, forcing color instead of JSON log output
You can install from source:
go install fortio.org/fortio@latestfortio (from your gopath bin/ directory, usually ~/go/bin)The releases page has binaries for many OS/architecture combinations (see assets):
curl -L https://github.com/fortio/fortio/releases/download/v1.75.2/fortio-linux_amd64-1.75.2.tgz \
| sudo tar -C / -xvzpf -
# or the debian package
wget https://github.com/fortio/fortio/releases/download/v1.75.2/fortio_1.75.2_amd64.deb
dpkg -i fortio_1.75.2_amd64.deb
# or the rpm
rpm -i https://github.com/fortio/fortio/releases/download/v1.75.2/fortio-1.75.2-1.x86_64.rpm
# and more, see assets in release page
On macOS you can also install Fortio using Homebrew:
brew install fortio
On Windows, download https://github.com/fortio/fortio/releases/download/v1.75.2/fortio_win_1.75.2.zip and extract fortio.exe to any location, then using the Windows Command Prompt:
fortio.exe server
(at the prompt, allow the Windows firewall to let connections in)
Once fortio server is running, you can visit its web UI at http://localhost:8080/fortio/
You can get a preview of the reporting/graphing UI at https://demo.fortio.org
Fortio can be a HTTP or gRPC load generator, gathering statistics using the load subcommand,
or start simple HTTP and gRPC ping servers, as well as a basic web UI, result graphing, TCP/UDP echo, proxies, https redirector,
with the server command or issue gRPC ping messages using the grpcping command.
It can also fetch a single URL's for debugging when using the curl command (or the -curl flag to the load command).
Likewise you can establish a single TCP (or Unix domain or UDP (use udp:// prefix)) connection using the nc command (like the standalone netcat package).
You can run just the redirector with redirect or just the TCP echo with tcp-echo.
If you saved JSON results (using the web UI or directly from the command line), you can browse and graph those results using the report command.
You can run interactive fortio.load() scripts using script or already written grol scripts, a simplified go like language, from a file, like
fortio script -init 'url="http://localhost:8080/"' scripting_example.gr
...
---- 🎉 Ramp up to 8000 qps done without error, actual qps 7993.678998 ----
---- 🎉 Ramp up to 9000 qps done without error, actual qps 8994.693886 ----
---- 🎉 Ramp up to 10000 qps done without error, actual qps 9996.013250 ----
See scripting_example.gr or the tests in cli_tests.txtar.
The version command will print the short print version. fortio buildinfo will print the full
build information.
Lastly, you can learn which flags are available using help command.
Most important flags for HTTP load generation:
| Flag | Description, example |
|---|---|
-qps rate |
Total Queries Per Seconds across all connections/threads or 0 for no wait/max qps |
-nocatchup |
Do not try to reach the target qps by going faster when the service falls behind and then recovers. Makes QPS an absolute ceiling even if the service has some spikes in latency, fortio will not compensate (but also won't stress the target more than the set qps). Recommended to use jointly with -uniform. |
-c connections |
Number of parallel simultaneous connections (and matching go routine) |
-t duration |
How long to run the test (for instance -t 30m for 30 minutes or -t 1d4h for 28h) or 0 to run until ^C, example (default 5s) |
-n numcalls |
Run for exactly this number of calls instead of duration. Default (0) is to use duration (-t). |
-payload str or -payload-file fname |
Switch to using POST with the given payload (see also -payload-size for random payload) |
-uniform |
Spread the calls in time across threads for a more uniform call distribution. Works even better in conjunction with -nocatchup. |
-r resolution |
Resolution of the histogram lowest buckets in seconds (default 0.001 i.e, 1ms), use 1/10th of your expected typical latency (and -offset if needed) |
-H "header: value" |
Can be specified multiple times to add headers (including Host:) |
-a |
Automatically save JSON result with filename based on labels and timestamp |
-json filename |
Filename or - for stdout to output JSON result (relative to -data-dir by default, should end with .json if you want fortio report to show them; using -a is typically a better option) |
-labels "l1 l2 ..." |
Additional config data/labels to add to the resulting JSON, defaults to target URL and hostname |
-h2 |
Client calls will attempt to negotiate HTTP/2 instead of HTTP/1.1, implies -stdclient |
-X method |
Change HTTP method to the one specified instead of automatic HTTP GET or POST based on -payload-* or -content-type |
-logger-force-color |
For interactive runs for color instead of JSON output |
-logger-no-color |
Force JSON output even when run from terminal |
Changing the HTTP options like the TLS options -cert, -key, -cacert when launching an echo/UI/rapi server will make these options the default for runs initiated from that server (or fetches/proxies etc.).
Full list of command line flags (fortio help):
Φορτίο 1.75.2 usage:
fortio command [flags] target
where command is one of: load (load testing), server (starts ui, rest api,
http-echo, redirect, proxies, tcp-echo, udp-echo and grpc ping servers),
tcp-echo (only the tcp-echo server), udp-echo (only udp-echo server),
report (report only UI server), redirect (only the redirect server),
proxies (only the -M and -P configured proxies), grpcping (gRPC client),
or curl (single URL debug), or nc (single tcp or udp:// connection),
or script (interactive grol script mode or script file),
or version (prints the full version and build details).
where target is a URL (http load tests) or host:port (grpc health test),
or tcp://host:port (tcp load test), or udp://host:port (udp load test).
or 1 of the special arguments
fortio {help|envhelp|version|buildinfo}
flags:
-H key:value
Additional HTTP header(s) or gRPC metadata. Multiple key:value pairs can be
passed using multiple -H.
-L Follow redirects (implies -std-client) - do not use for load test
-M value
HTTP multi proxy to run, e.g -M "localport1 baseDestURL1 baseDestURL2" -M ...
-P value
TCP proxies to run, e.g -P "localport1 dest_host1:dest_port1" -P "[::1]:0
www.google.com:443" ...
-X string
HTTP method to use instead of GET/POST depending on payload/content-type
-a Automatically save JSON result with filename based on labels & timestamp
-abort-on int
HTTP status code that if encountered aborts the run. e.g., 503 or -1 for socket
errors.
-access-log-file path
file path to log all requests to. Maybe have performance impacts
-access-log-format format
format for access log. Supported values: [json, influx] (default "json")
-allow-initial-errors
Allow and don't abort on initial warmup errors
-base-url URL
base URL used as prefix for data/index.tsv generation. (when empty, the URL from
the first request is used)
-c int
Number of connections/goroutine/threads (default 4)
-cacert Path
Path to a custom CA certificate file to be used for the TLS client connections,
if empty, use https:// prefix for standard internet/system CAs
-calc-qps
Calculate the qps based on number of requests (-n) and duration (-t)
-cert Path
Path to the certificate file to be used for client or server TLS
-compression
Enable HTTP compression
-config-dir directory
Config directory to watch for dynamic flag changes
-config-port port
Config port to open for dynamic flag UI/api
-connection-reuse min:max
Range min:max for the max number of connections to reuse for each thread, default
to unlimited. e.g. 10:30 means randomly choose a max connection reuse threshold between
10 and 30 requests.
-content-type string
Sets HTTP content type. Setting this value switches the request method from GET
to POST.
-curl
Just fetch the content once
-curl-stdout-headers
Restore pre 1.22 behavior where HTTP headers of the fast client are output to
stdout in curl mode. now stderr by default.
-data-dir Directory
Directory where JSON results are stored/read (default ".")
-dns-method method
When a name resolves to multiple ip, which method to pick: cached-rr for cached
round-robin, rnd for random, first for first answer (pre 1.30 behavior), rr for
round-robin. (default cached-rr)
-echo-debug-path URI
http echo server URI for debug, empty turns off that part (more secure) (default
"/debug")
-echo-server-default-params value
Default parameters/querystring to use if there isn't one provided explicitly. E.g
"status=404&delay=3s"
-gomaxprocs int
Setting for runtime.GOMAXPROCS, < 1 doesn't change the default
-grpc
Use gRPC (health check by default, add -ping for ping) for load testing
-grpc-compression
Enable$ claude mcp add fortio \
-- python -m otcore.mcp_server <graph>