diff --git a/performance-testing/.gitignore b/performance-testing/.gitignore new file mode 100644 index 0000000..ef7092e --- /dev/null +++ b/performance-testing/.gitignore @@ -0,0 +1 @@ +rsyslog.pid diff --git a/performance-testing/Apicast1kPOST.scala b/performance-testing/Apicast1kPOST.scala new file mode 100644 index 0000000..f4d9e8e --- /dev/null +++ b/performance-testing/Apicast1kPOST.scala @@ -0,0 +1,31 @@ +package itix + +import scala.concurrent.duration._ + +import io.gatling.core.Predef._ +import io.gatling.http.Predef._ +import io.gatling.jdbc.Predef._ + +class Apicast1kPOST extends Simulation { + + val httpProtocol = http + .baseURL("http://localhost:8080") + .inferHtmlResources() + .acceptHeader("*/*") + .contentTypeHeader("application/x-www-form-urlencoded") + .userAgentHeader("curl/7.54.0") + + + + + + val scn = scenario("Apicast1kPOST") + .repeat(1000) { + exec(http("POST-1k") + .post("/?user_key=secret") + .formParam("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "") + .check(status.is(200))) + } + + setUp(scn.inject(rampUsers(200) over(5 seconds))).protocols(httpProtocol) +} diff --git a/performance-testing/README.md b/performance-testing/README.md new file mode 100644 index 0000000..fc0a163 --- /dev/null +++ b/performance-testing/README.md @@ -0,0 +1,81 @@ +# Performance Testing + +## Setup + +- Download and install [gatling](http://gatling.io/). +- Edit `apicast/conf/nginx.conf` to set `worker_connections` to a much reasonable setting for a development machine +- Launch a development apicast with the following parameters: +``` +export APICAST_LOG_LEVEL=crit +export THREESCALE_CONFIG_FILE=config.json +sudo sysctl -w kern.maxfiles=65536 +sudo sysctl -w kern.maxfilesperproc=65536 +sudo launchctl limit maxfiles 65536 65536 +ulimit -n 65536 +bin/apicast -i 3600 -m on -w 8 &> apicast.log +``` + +**WARNING:** On MacOS, you have to run apicast **as root** to be able to push up +the maximum number of open files (`ulimit -n`). + +- Install and run a rsyslog server: +``` +sudo brew install rsyslog +/usr/local/Cellar/rsyslog/*/sbin/rsyslogd -4 -n -f rsyslog.conf -i "$PWD/rsyslog.pid" +``` + +## Recording a scenario (OPTIONAL) + +Gatling scenario are available in the [performance-testing directory](performance-testing). +However, you can record your own by : + +- Launcing the recorder and starting a recording +- Doing a test request through the gatling proxy +``` +export http_proxy=http://localhost:8000 +curl "http://localhost:8080/?user_key=secret" -D - -X POST -d "data" +``` + +Then, you can customize the scenario to loop over the request you recorded and +add virtual users. + +## Running a scenario against the vanilla apicast + +Run the gatling scenario: +``` +gatling.sh -sf . -s itix.Apicast1kPOST +``` + +## Running a scenario against the apicast with the logging module + +Then, re-start apicast with the following environment: +``` +export APICAST_MODULE=custom/verbose +export SYSLOG_HOST=127.0.0.1.xip.io +export SYSLOG_PORT=1601 +export SYSLOG_PROTO=tcp +export SYSLOG_PERIODIC_FLUSH=5 +export SYSLOG_FLUSH_LIMIT=10240 +``` + +Run the gatling scenario: +``` +gatling.sh -sf . -s itix.Apicast1kPOST +``` + +Check that you have exactly 200000 lines in both `apicast.log`: +- the one created by the apicast server +- the one created by the rsyslog server + +``` +$ wc -l apicast.log + 200000 apicast.log +``` + +## Reference + +- https://www.digitalocean.com/community/tutorials/how-to-optimize-nginx-configuration +- http://blog.martinfjordvald.com/2011/04/optimizing-nginx-for-high-traffic-loads/ +- http://gatling.io/docs/current/general/simulation_setup/#injection +- http://gatling.io/docs/current/cheat-sheet/ +- https://superuser.com/a/867865 diff --git a/performance-testing/config.json b/performance-testing/config.json new file mode 100644 index 0000000..4f24ee6 --- /dev/null +++ b/performance-testing/config.json @@ -0,0 +1,56 @@ +{ + "id": 1234567890987, + "provider_key": "provider-key", + "services": [ + { + "id": 654321, + "backend_version": "1", + "backend_authentication_type": "service_token", + "backend_authentication_value": "service-token-1234567890", + "proxy": { + "api_backend": "http://127.0.0.1:8081", + "auth_app_key": "app_key", + "auth_app_id": "app_id", + "auth_user_key": "user_key", + "credentials_location": "query", + "error_auth_failed": "Authentication failed", + "error_auth_missing": "Authentication parameters missing", + "error_status_auth_failed": 403, + "error_headers_auth_failed": "text/plain; charset=us-ascii", + "error_status_auth_missing": 403, + "error_headers_auth_missing": "text/plain; charset=us-ascii", + "error_no_match": "No Mapping Rule matched", + "error_status_no_match": 404, + "error_headers_no_match": "text/plain; charset=us-ascii", + "secret_token": "Shared_secret_sent_from_proxy_to_API_backend", + "hostname_rewrite": null, + "oauth_login_url": null, + "hosts": [ + "localhost" + ], + "backend": { + "endpoint": "http://127.0.0.1:8081", + "host": "backend" + }, + "proxy_rules": [ + { + "http_method": "GET", + "pattern": "/", + "metric_system_name": "hits", + "delta": 1, + "parameters": [], + "querystring_parameters": {} + }, + { + "http_method": "POST", + "pattern": "/", + "metric_system_name": "hits", + "delta": 1, + "parameters": [], + "querystring_parameters": {} + } + ] + } + } + ] +} diff --git a/performance-testing/rsyslog.conf b/performance-testing/rsyslog.conf new file mode 100644 index 0000000..7076546 --- /dev/null +++ b/performance-testing/rsyslog.conf @@ -0,0 +1,8 @@ +module(load="imtcp") + +ruleset(name="remote1"){ + action(type="omfile" file="/tmp/apicast.log") +} + + +input(type="imtcp" port="1601" ruleset="remote1" RateLimit.Interval="0" RateLimit.Burst="1000000000")