Fortio is a load testing tool that consists of:
- A server
- A client
- A GUI
- A load testing library
Fortio runs a specified number of queries per second (qps), records a histogram of execution time and calculates percentiles. It can run for a set duration, for a fixed number of calls, or until interrupted.
The server
command starts the grpc, http, and https redirector servers:
$ fortio server &
Fortio 0.8.0 grpc 'ping' server listening on [::]:8079
Fortio 0.8.0 https redirector server listening on [::]:8081
Fortio 0.8.0 echo server listening on [::]:8080
UI started - visit:
http://localhost:8080/fortio/ (or any host/ip reachable on this server)
21:45:23 I fortio_main.go:195> All fortio 0.8.0 buildinfo go1.10 servers started!
Docker example (with debug logging):
$ docker run --name fortio_server -p 8080:8080 -p 8079:8079 istio/fortio server -loglevel debug &
The /fortio
http endpoint serves the GUI and can be viewed from http://localhost:8080/fortio/
. The http echo server echos back data that it receives and is served from the /echo
endpoint. For example:
$ curl -d foo http://localhost:8080/echo/
foo
The 0.8 release added a TCP Proxy server. The server listens on a specified address:port and proxies TCP traffic to a remote address:port using the -P
flag:
# Remove the running fortio_server Docker container:
$ docker rm -f fortio_server
# Start Fortio server using -P to enable the TCP proxy.
# Note: Change "35.230.102.204:80" to your destination address:port
$ docker run --name fortio_server -p 8080:8080 -p 8079:8079 istio/fortio server -loglevel debug -P "$FORTIO_IP:8089 35.230.102.204:80" &
[1] 65810
$ 15:59:09 I logger.go:97> Log level is now 0 Debug (was 2 Info)
15:59:09 V stats.go:517> Will use [50 75 90 99 99.9] for percentiles
Fortio 0.8.1-pre grpc 'ping' server listening on [::]:8079
15:59:09 V uihandler.go:96> Using resources directory set at link time: /usr/local/lib/fortio
Fortio 0.8.1-pre https redirector server listening on [::]:8081
Fortio 0.8.1-pre echo server listening on [::]:8080
UI started - visit:
http://localhost:8080/fortio/ (or any host/ip reachable on this server)
Fortio 0.8.1-pre proxy for 35.230.102.204:80 server listening on 172.17.0.2:8089
15:59:09 D network.go:80> Host already an IP, will go to 35.230.102.204
15:59:09 I fortio_main.go:186> All fortio 0.8.1-pre 2018-03-20 22:32 0e1347b31d9eb6d190f29b81b2ee710697b6c6c3 go1.10 servers started!
Then curl
the Fortio proxy address:port:
# Get the IP of the Fortio server Docker container:
FORTIO_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' fortio_server)
$ docker run istio/fortio.fcurl:latest -loglevel debug -L http://$FORTIO_IP:8089/echo/
Fortio provides a grpc and an http client that is used to generate loads and collect statistics.
load
is the http client:
$ docker run istio/fortio:latest load http://$FORTIO_IP:8080/echo/
Fortio 0.3.6 running at 8 queries per second, 8->8 procs, for 5s: http://www.google.com
19:10:33 I httprunner.go:84> Starting http test for http://www.google.com with 4 threads at 8.0 qps
Starting at 8 qps with 4 thread(s) [gomax 8] for 5s : 10 calls each (total 40)
19:10:39 I periodic.go:314> T002 ended after 5.056753279s : 10 calls. qps=1.9775534712220633
19:10:39 I periodic.go:314> T001 ended after 5.058085991s : 10 calls. qps=1.9770324224999916
19:10:39 I periodic.go:314> T000 ended after 5.058796046s : 10 calls. qps=1.9767549252963101
19:10:39 I periodic.go:314> T003 ended after 5.059557593s : 10 calls. qps=1.9764573910247019
Ended after 5.059691387s : 40 calls. qps=7.9056
Sleep times : count 36 avg 0.49175757 +/- 0.007217 min 0.463508712 max 0.502087879 sum 17.7032725
Aggregated Function Time : count 40 avg 0.060587641 +/- 0.006564 min 0.052549016 max 0.089893269 sum 2.42350566
# range, mid point, percentile, count
>= 0.052549 < 0.06 , 0.0562745 , 47.50, 19
>= 0.06 < 0.07 , 0.065 , 92.50, 18
>= 0.07 < 0.08 , 0.075 , 97.50, 2
>= 0.08 <= 0.0898933 , 0.0849466 , 100.00, 1
# target 50% 0.0605556
# target 75% 0.0661111
# target 99% 0.085936
# target 99.9% 0.0894975
Code 200 : 40
Response Header Sizes : count 40 avg 690.475 +/- 15.77 min 592 max 693 sum 27619
Response Body/Total Sizes : count 40 avg 12565.2 +/- 301.9 min 12319 max 13665 sum 502608
All done 40 calls (plus 4 warmup) 60.588 ms avg, 7.9 qps
grcping
is the grpc client used for generating loads to a grpc server endpoint:
$ docker run istio/fortio:latest grpcping $FORTIO_IP
Clock skew histogram usec : count 1 avg 94.837 +/- 0 min 94.837 max 94.837 sum 94.837
# range, mid point, percentile, count
>= 94.837 <= 94.837 , 94.837 , 100.00, 1
# target 50% 94.837
RTT histogram usec : count 3 avg 887.94233 +/- 214.7 min 716.047 max 1190.582 sum 2663.827
# range, mid point, percentile, count
>= 716.047 <= 800 , 758.024 , 66.67, 2
> 1000 <= 1190.58 , 1095.29 , 100.00, 1
# target 50% 758.024
19:52:22 I pingsrv.go:114> Ping RTT 887942 (avg of 757198, 716047, 1190582 ns) clock skew 94837
A fcurl minimal curl client binary was added in the latest (v0.8) release. The compressed image size is roughly 2MB. This client is the same as fortio curl
$ docker run istio/fortio.fcurl:latest -loglevel debug -L http://$FORTIO_IP:8080/echo/
15:35:29 I logger.go:97> Log level is now 0 Debug (was 2 Info)
15:35:29 V http_client.go:86> URLSchemeCheck &{URL:http://172.17.0.2:8080/echo/ NumConnections:1 Compression:false DisableFastClient:true HTTP10:false DisableKeepAlive:false AllowHalfClose:false Insecure:false FollowRedirects:true initDone:true https:false extraHeaders:map[User-Agent:[istio/fortio-0.8.1]] hostOverride: HTTPReqTimeOut:15s}
15:35:29 V http_client.go:86> URLSchemeCheck &{URL:http://172.17.0.2:8080/echo/ NumConnections:1 Compression:false DisableFastClient:true HTTP10:false DisableKeepAlive:false AllowHalfClose:false Insecure:false FollowRedirects:true initDone:true https:false extraHeaders:map[User-Agent:[istio/fortio-0.8.1]] hostOverride: HTTPReqTimeOut:15s}
15:35:29 D http_client.go:202> For URL http://172.17.0.2:8080/echo/, sending:
GET /echo/ HTTP/1.1
Host: 172.17.0.2:8080
User-Agent: istio/fortio-0.8.1
Accept-Encoding: gzip
15:35:29 D http_client.go:253> For URL http://172.17.0.2:8080/echo/, received:
HTTP/1.1 200 OK
Date: Wed, 21 Mar 2018 15:35:29 GMT
Content-Length: 0
15:35:29 D http_client.go:268> Got 200 : 200 OK for http://172.17.0.2:8080/echo/ - response is 0 bytes
15:35:29 V commonflags.go:101> Fetch result code 200, data len 0, headerlen 0
The minimal fcurl
client is the same fortio curl
client:
$ docker run istio/fortio:latest curl -loglevel debug -L http://$FORTIO_IP:8080/echo/
5:35:29 I logger.go:97> Log level is now 0 Debug (was 2 Info)
15:35:29 V http_client.go:86> URLSchemeCheck &{URL:http://172.17.0.2:8080/echo/ NumConnections:1 Compression:false DisableFastClient:true HTTP10:false DisableKeepAlive:false AllowHalfClose:false Insecure:false FollowRedirects:true initDone:true https:false extraHeaders:map[User-Agent:[istio/fortio-0.8.1]] hostOverride: HTTPReqTimeOut:15s}
15:35:29 V http_client.go:86> URLSchemeCheck &{URL:http://172.17.0.2:8080/echo/ NumConnections:1 Compression:false DisableFastClient:true HTTP10:false DisableKeepAlive:false AllowHalfClose:false Insecure:false FollowRedirects:true initDone:true https:false extraHeaders:map[User-Agent:[istio/fortio-0.8.1]] hostOverride: HTTPReqTimeOut:15s}
15:35:29 D http_client.go:202> For URL http://172.17.0.2:8080/echo/, sending:
GET /echo/ HTTP/1.1
Host: 172.17.0.2:8080
User-Agent: istio/fortio-0.8.1
Accept-Encoding: gzip
15:35:29 D http_client.go:253> For URL http://172.17.0.2:8080/echo/, received:
HTTP/1.1 200 OK
Date: Wed, 21 Mar 2018 15:35:29 GMT
Content-Length: 0
15:35:29 D http_client.go:268> Got 200 : 200 OK for http://172.17.0.2:8080/echo/ - response is 0 bytes
15:35:29 V commonflags.go:101> Fetch result code 200, data len 0, headerlen 0
forexample is an example Fortio library implementation. Results of test run.
istio/tools/setup_perf_cluster.sh
deploys a GKE cluster, an Istio service mesh and a GCE VM. The script then runs Fortio on the VM, 2 pods within the cluster (non-Istio) and 2 pods within the Istio mesh.
Download and untar the Istio release (for Mac):
$ RELEASE=0.6
$ wget https://github.com/istio/istio/releases/download/$RELEASE/istio-$RELEASE.0-osx.tar.gz
$ tar -xvf istio-$RELEASE.0-osx.tar.gz
Copy the istioctl
client binary to your $PATH:
$ cp istio-$RELEASE.0/bin/istioctl /usr/local/bin/istioctl
Clone the Istio repo, which contains the perf cluster setup script:
$ git clone -b release-$RELEASE https://github.com/istio/istio.git
Source the script:
$ source istio/tools/setup_perf_cluster.sh
Run the setup_all
function:
$ setup_all
Obtaining latest ubuntu xenial image name... (takes a few seconds)...
Creating VM_NAME=fortio-vm using VM_IMAGE=https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/images/ubuntu-1604-xenial-v20180306
<SNIP>
Run the get_ips
function:
$ get_ips
+++ VM Ip is 35.230.102.204 - visit http://35.230.102.204/fortio/
+++ In k8s fortio external ip: http://35.230.62.254:8080/fortio/
+++ In k8s non istio ingress: http://35.227.220.111/fortio/
+++ In k8s istio ingress: http://35.230.50.21/fortio1/fortio/ and fortio2
Test access to the IPs with curl
or your web browser.