diff --git a/Dockerfile b/Dockerfile index c9a3022..b27e823 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,34 +1,27 @@ -FROM ubuntu:16.04 -MAINTAINER elvis@magic.io +FROM python:3.5 -RUN DEBIAN_FRONTEND=noninteractive \ - apt-get update && apt-get install -y \ - language-pack-en - -ENV LANG en_US.UTF-8 ENV WORKON_HOME /usr/local/python-venvs -ENV GOMAXPROCS 1 - -RUN mkdir -p /usr/local/python-venvs -RUN mkdir -p /usr/go/ ENV GOPATH /usr/go/ - -RUN DEBIAN_FRONTEND=noninteractive \ - apt-get update && apt-get install -y \ - autoconf automake libtool build-essential \ - python3 python3-pip git nodejs golang gosu - -RUN pip3 install vex -RUN vex --python=python3.5 -m bench pip install -U pip -RUN mkdir -p /var/lib/cache/pip +ENV GOMAXPROCS 1 ADD servers /usr/src/servers -RUN cd /usr/src/servers && go build goecho.go && \ - go get github.com/golang/groupcache/lru && go build gohttp.go -RUN vex bench pip --cache-dir=/var/lib/cache/pip \ - install -r /usr/src/servers/requirements.txt -RUN vex bench pip freeze -r /usr/src/servers/requirements.txt +RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \ + autoconf automake libtool build-essential nodejs golang + +RUN mkdir -p /usr/local/python-venvs \ + && mkdir -p /usr/go \ + && pip3 install vex \ + && vex --python=python3.5 -m bench pip install -U pip \ + && mkdir -p /var/lib/cache/pip \ + && vex bench pip --cache-dir=/var/lib/cache/pip install -r /usr/src/servers/requirements.txt \ + && vex bench pip freeze -r /usr/src/servers/requirements.txt \ + && curl -L -o /usr/local/bin/gosu https://github.com/tianon/gosu/releases/download/1.10/gosu-$(dpkg --print-architecture | awk -F- '{ print $NF }') \ + && chmod +x /usr/local/bin/gosu \ + && cd /usr/src/servers \ + && go build goecho.go \ + && go get github.com/golang/groupcache/lru \ + && go build gohttp.go EXPOSE 25000 @@ -37,4 +30,4 @@ VOLUME /tmp/sockets ENTRYPOINT ["/entrypoint"] -ADD entrypoint /entrypoint +ADD entrypoint /entrypoint \ No newline at end of file diff --git a/README.rst b/README.rst index 8b1d150..64cda79 100755 --- a/README.rst +++ b/README.rst @@ -7,18 +7,160 @@ network performance of a variety of server frameworks. The servers are run inside a Docker container for environment stability, so to use this toolbench you need a reasonably recent Docker. +HTTP Servers Tested +------------------- + +- HTML Report : http://espace-groupware.com/docs/vmbench/report-http.html +- Json Report : http://espace-groupware.com/docs/vmbench/report-http.json + +=================== ==================== ============= +Product Benchmark Key Comments +=================== ==================== ============= +`AioHTTP/asyncio`_ http-asyncio-aiohttp +`AioHTTP/uvloop`_ http-uvloop-aiohttp +`Sanic`_ http-sanic uvloop +`Sanic`_ http-sanic-workers uvloop / multi-workers +`Gevent/WSGI`_ http-gevent-wsgi +`Gevent/Flask`_ http-gevent-flask +`Node.js`_ http-nodejs http module - Node.js 0.10.29 +`Golang`_ http-golang net/http - Golang 2:1.3.3 +=================== ==================== ============= + +.. _`AioHTTP/asyncio`: http://aiohttp.readthedocs.io +.. _`AioHTTP/uvloop`: https://github.com/MagicStack/uvloop +.. _`Sanic`: https://github.com/channelcat/sanic +.. _`Gevent/WSGI`: http://gevent.org/ +.. _`Gevent/Flask`: http://flask.pocoo.org +.. _`Node.js`: https://nodejs.org/ +.. _`Golang`: https://golang.org/ + +Screenshots +----------- + +Requests/Seconds +:::::::::::::::: + +.. image:: http://espace-groupware.com/docs/vmbench/http-report-requests.png + :align: center + +Latency +::::::: + +.. image:: http://espace-groupware.com/docs/vmbench/http-report-latency.png + :align: center + + +Test Server Description +----------------------- + +Information complémentaire sur les différences obtenues par rapport au test original sur https://magic.io/blog/uvloop-blazing-fast-python-networking/http-bench.html + +- magic.io: Linux 4.4.5 (Ubuntu 16.04, x86_64) on Intel(R) Xeon(R) CPU E5-1620 v2 @ 3.70GHz + +- Me: Linux 4.4.0-57-generic (Docker/Debian 8.7, x86_64) on Intel(R) Xeon(R) CPU W3520 @ 2.67GHz + +My server: (https://www.soyoustart.com/fr/offres/142sys4.xml) + +- OVH - So you Start - 16G ECC - Intel(R) Xeon(R) CPU W3520 @ 2.67GHz 4c/8t SoftRaid 2x2 To + Installation ------------ -Install the following: +Requirements: -- Docker -- Python 3 +- Docker (tested on Docker 17.04.0-ce / Ubuntu 16.04) +- Python 3 (tested on Python 3.5.3 64bits) +- Wrk (tested on Wrk 4.0.1) - Numpy -Build the docker image containing the servers being tested by running -``./build.sh``. +:: + + $ apt-get install -y python3-numpy wrk + + $ git clone -b add_features https://github.com/srault95/vmbench + + $ cd vmbench + + # Build the docker image containing the servers + # being tested by running + $ ./build.sh + +Running Tests +------------- + +:: + + # The benchmarks can then be ran with + $ ./run_benchmarks --help + + # Example for run all http tests: + $ ./run_benchmarks --save-html report-http.html --benchmarks http-* + + # Run one test for Sanic Http Server with duration (30sec) + # and concurency (300) + $ ./run_benchmarks --save-html report-http.html \ + --benchmarks http-uvloop-aiohttp \ + --duration 30 --concurrency-levels 300 + +Debug +----- + +Pour la mise au point des services à tester, vous pouvez lancement manuellement +le container Docker comme le ferait le script ``run_benchmark`` + +Avec un volume vers $PWD/servers:/usr/src/servers, vous pouvez éditer les services +sans relancer le build de l'image Docker. + +:: + + # Update docker image: magic/benchmark + $ ./build.sh + + $ docker run --rm -it -p 25000:25000 -e UID=0 -e GID=0 \ + -v $PWD/servers:/usr/src/servers \ + -v $PWD/.cache:/var/lib/cache \ + -v $PWD/sockets:/tmp/sockets magic/benchmark \ + vex bench python /usr/src/servers/sanic_http_server.py --addr=0.0.0.0:25000 --worker=1 + + # Go to navigator and open http://YOUR_IP:25000/[MSIZE] + # http://YOUR_IP:25000/1024 + + # Or run the http_client/echo_client + $ ./http_client --output-format=json --addr=127.0.0.1:25000 \ + --msize=1024 --concurrency=300 --duration=30 + +Python Libraries Version +------------------------ + +:: + + $ docker run --rm -it magic/benchmark vex bench pip freeze -The benchmarks can then be ran with ``./run_benchmarks``. Use -``./run_benchmarks --help`` for various options, including selective -benchmark running. + aiofiles==0.3.1 + aiohttp==2.0.7 + appdirs==1.4.3 + async-timeout==1.2.1 + chardet==3.0.3 + click==6.7 + curio==0.4 + Flask==0.12.2 + gevent==1.2.1 + greenlet==0.4.12 + httptools==0.0.9 + itsdangerous==0.24 + Jinja2==2.9.6 + MarkupSafe==1.0 + multidict==2.1.5 + packaging==16.8 + pyparsing==2.2.0 + sanic==0.5.4 + six==1.10.0 + tornado==4.5.1 + Twisted==16.1.1 + ujson==1.35 + uvloop==0.8.0 + websockets==3.3 + Werkzeug==0.12.2 + yarl==0.10.2 + zope.interface==4.4.1 + diff --git a/report/http-report-latency.png b/report/http-report-latency.png new file mode 100644 index 0000000..f8ef396 Binary files /dev/null and b/report/http-report-latency.png differ diff --git a/report/http-report-requests.png b/report/http-report-requests.png new file mode 100644 index 0000000..8e6eede Binary files /dev/null and b/report/http-report-requests.png differ diff --git a/report/report-http.html b/report/report-http.html new file mode 100644 index 0000000..18bb76a --- /dev/null +++ b/report/report-http.html @@ -0,0 +1,707 @@ + + + + + + + + + + + + +

Sun May 21 19:08:34 2017

+ +

Server Performance Benchmark Report

+ +Below are the results of testing network server implementations. Each server +is constrained to run in a single process. + +Test environment: Linux 4.4.0-57-generic (debian 8.7, x86_64) on . + +

Results

+ + + + +

Detailed Benchmark Data

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
http
1.0KiB, c 30010.0KiB, c 300100.0KiB, c 300
asyncio aiohttp
Requests/sec2982.02921.032640.53
Transfer/sec3.3MiB28.91MiB258.22MiB
Min latency30.096ms34.152ms21.816ms
Mean latency106.632ms102.282ms121.298ms
Max latency1164.909ms195.624ms1290.909ms
Latency variation76.459ms (71.7%)3.545ms (3.47%)90.09ms (74.27%)
uvloop aiohttp
Requests/sec3288.273152.592765.92
Transfer/sec3.64MiB31.2MiB270.48MiB
Min latency34.529ms2.993ms25.15ms
Mean latency90.848ms94.888ms107.994ms
Max latency207.112ms203.372ms229.753ms
Latency variation20.577ms (22.65%)16.073ms (16.94%)4.763ms (4.41%)
sanic
Requests/sec10477.938959.795471.73
Transfer/sec11.45MiB88.55MiB535.0MiB
Min latency11.304ms3.155ms4.466ms
Mean latency28.554ms33.378ms54.638ms
Max latency65.616ms72.987ms141.002ms
Latency variation4.06ms (14.22%)4.179ms (12.52%)3.27ms (5.99%)
sanic workers
Requests/sec29239.5123834.7110775.43
Transfer/sec31.96MiB235.56MiB1053.56MiB
Min latency0.427ms0.328ms0.846ms
Mean latency10.226ms12.736ms28.029ms
Max latency36.814ms45.612ms146.098ms
Latency variation3.562ms (34.84%)6.837ms (53.68%)14.601ms (52.09%)
gevent wsgi
Requests/sec2135.272259.632052.74
Transfer/sec2.3MiB22.29MiB200.67MiB
Min latency3.669ms0.364ms0.436ms
Mean latency140.54ms135.284ms153.974ms
Max latency1152.94ms603.438ms1480.412ms
Latency variation31.398ms (22.34%)63.219ms (46.73%)97.479ms (63.31%)
gevent flask
Requests/sec1401.911477.691362.06
Transfer/sec1.56MiB14.63MiB133.2MiB
Min latency36.726ms0.609ms0.678ms
Mean latency217.132ms207.326ms227.063ms
Max latency1358.473ms1278.197ms1637.495ms
Latency variation74.65ms (34.38%)107.136ms (51.68%)111.522ms (49.12%)
nodejs
Requests/sec7764.387367.386458.74
Transfer/sec0.84MiB0.79MiB0.7MiB
Min latency6.192ms5.822ms5.747ms
Mean latency38.495ms40.596ms46.302ms
Max latency61.974ms66.967ms77.724ms
Latency variation1.085ms (2.82%)3.792ms (9.34%)3.895ms (8.41%)
golang
Requests/sec26079.516709.3910866.54
Transfer/sec28.43MiB165.38MiB1062.63MiB
Min latency0.091ms0.097ms0.175ms
Mean latency11.474ms17.914ms27.55ms
Max latency26.679ms41.076ms120.607ms
Latency variation3.084ms (26.88%)4.838ms (27.0%)6.521ms (23.67%)
+ + + + + + + diff --git a/report/report-http.json b/report/report-http.json new file mode 100644 index 0000000..7676612 --- /dev/null +++ b/report/report-http.json @@ -0,0 +1 @@ +{"platform": {"system": "Linux 4.4.0-57-generic", "arch": "x86_64", "cpu": "", "distribution": "debian 8.7"}, "concurrency_levels": [300], "benchmarks": [{"variations": [{"latency_max": 1164.909, "messages": 89702, "latency_mean": 106.632, "latency_cv": 71.7, "latency_min": 30.096, "latency_percentiles": [[25.0, 98.981], [50.0, 99.161], [75.0, 101.077], [90.0, 101.383], [99.0, 442.815], [99.99, 1162.1]], "latency_std": 76.459, "transfer": 3.3, "rps": 2982.0}, {"latency_max": 195.624, "messages": 87869, "latency_mean": 102.282, "latency_cv": 3.47, "latency_min": 34.152, "latency_percentiles": [[25.0, 101.198], [50.0, 101.402], [75.0, 103.32], [90.0, 103.555], [99.0, 112.105], [99.99, 193.473]], "latency_std": 3.545, "transfer": 28.91, "rps": 2921.03}, {"latency_max": 1290.909, "messages": 79385, "latency_mean": 121.298, "latency_cv": 74.27, "latency_min": 21.816, "latency_percentiles": [[25.0, 111.7], [50.0, 111.872], [75.0, 113.874], [90.0, 114.112], [99.0, 601.906], [99.99, 1290.173]], "latency_std": 90.09, "transfer": 258.22, "rps": 2640.53}], "name": "http-asyncio-aiohttp"}, {"variations": [{"latency_max": 207.112, "messages": 98945, "latency_mean": 90.848, "latency_cv": 22.65, "latency_min": 34.529, "latency_percentiles": [[25.0, 74.524], [50.0, 91.187], [75.0, 93.024], [90.0, 125.849], [99.0, 151.61], [99.99, 204.644]], "latency_std": 20.577, "transfer": 3.64, "rps": 3288.27}, {"latency_max": 203.372, "messages": 94855, "latency_mean": 94.888, "latency_cv": 16.94, "latency_min": 2.993, "latency_percentiles": [[25.0, 93.862], [50.0, 94.913], [75.0, 96.338], [90.0, 99.111], [99.0, 157.599], [99.99, 194.156]], "latency_std": 16.073, "transfer": 31.2, "rps": 3152.59}, {"latency_max": 229.753, "messages": 83206, "latency_mean": 107.994, "latency_cv": 4.41, "latency_min": 25.15, "latency_percentiles": [[25.0, 106.581], [50.0, 107.061], [75.0, 108.226], [90.0, 109.034], [99.0, 122.935], [99.99, 214.479]], "latency_std": 4.763, "transfer": 270.48, "rps": 2765.92}], "name": "http-uvloop-aiohttp"}, {"variations": [{"latency_max": 65.616, "messages": 315178, "latency_mean": 28.554, "latency_cv": 14.22, "latency_min": 11.304, "latency_percentiles": [[25.0, 28.284], [50.0, 28.546], [75.0, 28.773], [90.0, 29.054], [99.0, 48.144], [99.99, 62.991]], "latency_std": 4.06, "transfer": 11.45, "rps": 10477.93}, {"latency_max": 72.987, "messages": 269611, "latency_mean": 33.378, "latency_cv": 12.52, "latency_min": 3.155, "latency_percentiles": [[25.0, 31.088], [50.0, 33.438], [75.0, 33.726], [90.0, 36.846], [99.0, 57.069], [99.99, 68.185]], "latency_std": 4.179, "transfer": 88.55, "rps": 8959.79}, {"latency_max": 141.002, "messages": 164592, "latency_mean": 54.638, "latency_cv": 5.99, "latency_min": 4.466, "latency_percentiles": [[25.0, 53.717], [50.0, 53.873], [75.0, 54.11], [90.0, 59.104], [99.0, 61.278], [99.99, 120.234]], "latency_std": 3.27, "transfer": 535.0, "rps": 5471.73}], "name": "http-sanic"}, {"variations": [{"latency_max": 36.814, "messages": 879476, "latency_mean": 10.226, "latency_cv": 34.84, "latency_min": 0.427, "latency_percentiles": [[25.0, 7.532], [50.0, 9.905], [75.0, 12.324], [90.0, 14.881], [99.0, 20.433], [99.99, 29.463]], "latency_std": 3.562, "transfer": 31.96, "rps": 29239.51}, {"latency_max": 45.612, "messages": 716675, "latency_mean": 12.736, "latency_cv": 53.68, "latency_min": 0.328, "latency_percentiles": [[25.0, 7.104], [50.0, 11.507], [75.0, 16.854], [90.0, 22.479], [99.0, 32.028], [99.99, 44.451]], "latency_std": 6.837, "transfer": 235.56, "rps": 23834.71}, {"latency_max": 146.098, "messages": 323347, "latency_mean": 28.029, "latency_cv": 52.09, "latency_min": 0.846, "latency_percentiles": [[25.0, 17.056], [50.0, 25.304], [75.0, 35.668], [90.0, 47.195], [99.0, 74.529], [99.99, 108.486]], "latency_std": 14.601, "transfer": 1053.56, "rps": 10775.43}], "name": "http-sanic-workers"}, {"variations": [{"latency_max": 1152.94, "messages": 64225, "latency_mean": 140.54, "latency_cv": 22.34, "latency_min": 3.669, "latency_percentiles": [[25.0, 131.979], [50.0, 139.982], [75.0, 147.913], [90.0, 159.996], [99.0, 183.899], [99.99, 1149.765]], "latency_std": 31.398, "transfer": 2.3, "rps": 2135.27}, {"latency_max": 603.438, "messages": 67972, "latency_mean": 135.284, "latency_cv": 46.73, "latency_min": 0.364, "latency_percentiles": [[25.0, 133.017], [50.0, 134.93], [75.0, 139.569], [90.0, 163.852], [99.0, 331.333], [99.99, 603.378]], "latency_std": 63.219, "transfer": 22.29, "rps": 2259.63}, {"latency_max": 1480.412, "messages": 61756, "latency_mean": 153.974, "latency_cv": 63.31, "latency_min": 0.436, "latency_percentiles": [[25.0, 143.97], [50.0, 144.591], [75.0, 149.361], [90.0, 158.348], [99.0, 703.72], [99.99, 1463.128]], "latency_std": 97.479, "transfer": 200.67, "rps": 2052.74}], "name": "http-gevent-wsgi"}, {"variations": [{"latency_max": 1358.473, "messages": 42151, "latency_mean": 217.132, "latency_cv": 34.38, "latency_min": 36.726, "latency_percentiles": [[25.0, 203.991], [50.0, 212.229], [75.0, 220.035], [90.0, 227.916], [99.0, 455.113], [99.99, 1353.692]], "latency_std": 74.65, "transfer": 1.56, "rps": 1401.91}, {"latency_max": 1278.197, "messages": 44437, "latency_mean": 207.326, "latency_cv": 51.68, "latency_min": 0.609, "latency_percentiles": [[25.0, 205.567], [50.0, 213.702], [75.0, 223.562], [90.0, 242.716], [99.0, 554.723], [99.99, 1271.393]], "latency_std": 107.136, "transfer": 14.63, "rps": 1477.69}, {"latency_max": 1637.495, "messages": 40981, "latency_mean": 227.063, "latency_cv": 49.12, "latency_min": 0.678, "latency_percentiles": [[25.0, 217.616], [50.0, 222.234], [75.0, 229.334], [90.0, 239.396], [99.0, 831.777], [99.99, 1633.546]], "latency_std": 111.522, "transfer": 133.2, "rps": 1362.06}], "name": "http-gevent-flask"}, {"variations": [{"latency_max": 61.974, "messages": 233635, "latency_mean": 38.495, "latency_cv": 2.82, "latency_min": 6.192, "latency_percentiles": [[25.0, 38.188], [50.0, 38.333], [75.0, 38.515], [90.0, 38.804], [99.0, 41.685], [99.99, 58.164]], "latency_std": 1.085, "transfer": 0.84, "rps": 7764.38}, {"latency_max": 66.967, "messages": 221574, "latency_mean": 40.596, "latency_cv": 9.34, "latency_min": 5.822, "latency_percentiles": [[25.0, 39.26], [50.0, 39.404], [75.0, 39.632], [90.0, 41.903], [99.0, 53.893], [99.99, 63.216]], "latency_std": 3.792, "transfer": 0.79, "rps": 7367.38}, {"latency_max": 77.724, "messages": 194204, "latency_mean": 46.302, "latency_cv": 8.41, "latency_min": 5.747, "latency_percentiles": [[25.0, 44.378], [50.0, 44.851], [75.0, 45.675], [90.0, 54.84], [99.0, 58.121], [99.99, 76.755]], "latency_std": 3.895, "transfer": 0.7, "rps": 6458.74}], "name": "http-nodejs"}, {"variations": [{"latency_max": 26.679, "messages": 784109, "latency_mean": 11.474, "latency_cv": 26.88, "latency_min": 0.091, "latency_percentiles": [[25.0, 8.935], [50.0, 11.394], [75.0, 13.815], [90.0, 15.291], [99.0, 19.336], [99.99, 23.705]], "latency_std": 3.084, "transfer": 28.43, "rps": 26079.5}, {"latency_max": 41.076, "messages": 502243, "latency_mean": 17.914, "latency_cv": 27.0, "latency_min": 0.097, "latency_percentiles": [[25.0, 13.989], [50.0, 17.822], [75.0, 21.623], [90.0, 23.886], [99.0, 30.242], [99.99, 39.332]], "latency_std": 4.838, "transfer": 165.38, "rps": 16709.39}, {"latency_max": 120.607, "messages": 326673, "latency_mean": 27.55, "latency_cv": 23.67, "latency_min": 0.175, "latency_percentiles": [[25.0, 22.288], [50.0, 27.538], [75.0, 32.625], [90.0, 35.711], [99.0, 41.824], [99.99, 91.084]], "latency_std": 6.521, "transfer": 1062.63, "rps": 10866.54}], "name": "http-golang"}], "date": "%Y-%m-%dT%H:%M:%S%z", "payload_size_levels": [1024, 10240, 102400], "duration": 30} \ No newline at end of file diff --git a/run_benchmarks b/run_benchmarks index e38641b..8785c69 100755 --- a/run_benchmarks +++ b/run_benchmarks @@ -1,6 +1,5 @@ #!/usr/bin/env python3 - import argparse import collections import datetime @@ -172,32 +171,64 @@ benchmarks = [{ }, { 'name': 'http-asyncio-aiohttp', 'title': 'HTTP server (asyncio/aiohttp)', - 'server': python + ['/usr/src/servers/asyncio_http_server.py', + 'server': python + ['/usr/src/servers/aio_http_server.py', '--type=asyncio+aiohttp', '--addr=0.0.0.0:25000'], 'server_address': tcp_address, 'client': http_client, -}, { - 'name': 'http-asyncio-httptools', - 'title': 'HTTP server (asyncio/httptools)', - 'server': python + ['/usr/src/servers/asyncio_http_server.py', - '--type=asyncio+httptools', +}, +#{ +# 'name': 'http-asyncio-httptools', +# 'title': 'HTTP server (asyncio/httptools)', +# 'server': python + ['/usr/src/servers/asyncio_http_server.py', +# '--type=asyncio+httptools', +# '--addr=0.0.0.0:25000'], +# 'server_address': tcp_address, +# 'client': http_client, +{ + 'name': 'http-uvloop-aiohttp', + 'title': 'HTTP server (uvloop/aiohttp)', + 'server': python + ['/usr/src/servers/aio_http_server.py', + '--type=uvloop+aiohttp', + '--addr=0.0.0.0:25000'], + 'server_address': tcp_address, + 'client': http_client, +}, +#{ +# 'name': 'http-uvloop-httptools', +# 'title': 'HTTP server (uvloop/httptools)', +# 'server': python + ['/usr/src/servers/asyncio_http_server.py', +# '--type=uvloop+httptools', +# '--addr=0.0.0.0:25000'], +# 'server_address': tcp_address, +# 'client': http_client, +#}, +{ + 'name': 'http-sanic', + 'title': 'HTTP server (sanic)', + 'server': python + ['/usr/src/servers/sanic_http_server.py', '--addr=0.0.0.0:25000'], 'server_address': tcp_address, 'client': http_client, }, { - 'name': 'http-uvloop-aiohttp', - 'title': 'HTTP server (uvloop/aiohttp)', - 'server': python + ['/usr/src/servers/asyncio_http_server.py', - '--type=uvloop+aiohttp', + 'name': 'http-sanic-workers', + 'title': 'HTTP server (sanic workers)', + 'server': python + ['/usr/src/servers/sanic_http_server.py', + '--addr=0.0.0.0:25000', + '--worker=4'], + 'server_address': tcp_address, + 'client': http_client, +}, { + 'name': 'http-gevent-wsgi', + 'title': 'HTTP server (gevent/wsgi)', + 'server': python + ['/usr/src/servers/gevent_http_server.py', '--addr=0.0.0.0:25000'], 'server_address': tcp_address, 'client': http_client, }, { - 'name': 'http-uvloop-httptools', - 'title': 'HTTP server (uvloop/httptools)', - 'server': python + ['/usr/src/servers/asyncio_http_server.py', - '--type=uvloop+httptools', + 'name': 'http-gevent-flask', + 'title': 'HTTP server (gevent/flask)', + 'server': python + ['/usr/src/servers/gevent_http_flask.py', '--addr=0.0.0.0:25000'], 'server_address': tcp_address, 'client': http_client, @@ -297,7 +328,7 @@ def kill_server(): if server_container_exists(): print('Removing server container...') - subprocess.check_output(['docker', 'rm', 'magicbench']) + subprocess.check_output(['docker', 'rm', '-f', 'magicbench']) def format_report(data, target_file): diff --git a/servers/aio_http_server.py b/servers/aio_http_server.py new file mode 100644 index 0000000..d415c2a --- /dev/null +++ b/servers/aio_http_server.py @@ -0,0 +1,96 @@ + +import sys +import argparse +import asyncio + +from aiohttp.web import Application, Response, StreamResponse, run_app + +async def index(request): + resp = StreamResponse() + msize = 1024 + try: + msize = int(request.match_info.get('msize', '1024')) + except: + pass + #answer = ('Hello, ' + name).encode('utf8') + answer = b'X' * msize + resp.content_length = len(answer) + resp.content_type = 'text/plain' + await resp.prepare(request) + resp.write(answer) + await resp.write_eof() + return resp + +def abort(msg): + print(msg, file=sys.stderr) + sys.exit(1) + +async def init(loop): + app = Application() + app.router.add_get('/{msize}', index) + return app + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--type', default='asyncio+aiohttp', action='store') + parser.add_argument('--addr', default='127.0.0.1:25000', type=str) + args = parser.parse_args() + + if args.type: + parts = args.type.split('+') + if len(parts) > 1: + loop_type = parts[0] + server_type = parts[1] + else: + server_type = args.type + + if server_type in {'aiohttp', 'httptools'}: + if not loop_type: + loop_type = 'asyncio' + else: + loop_type = None + + if loop_type not in {'asyncio', 'uvloop'}: + abort('unrecognized loop type: {}'.format(loop_type)) + + if server_type not in {'aiohttp', 'httptools'}: + abort('unrecognized server type: {}'.format(server_type)) + + if loop_type: + if loop_type == "uvloop": + import uvloop + loop = uvloop.new_event_loop() + else: + loop = globals()[loop_type].new_event_loop() + else: + loop = None + + print('using {} loop: {!r}'.format(loop_type, loop)) + print('using {} HTTP server'.format(server_type)) + + if loop: + asyncio.set_event_loop(loop) + loop.set_debug(False) + + unix = False + if args.addr.startswith('file:'): + unix = True + addr = args.addr[5:] + else: + addr = args.addr.split(':') + addr[1] = int(addr[1]) + addr = tuple(addr) + + print('serving on: {}'.format(addr)) + + if loop: + try: + loop = asyncio.get_event_loop() + app = loop.run_until_complete(init(loop)) + run_app(app, host="0.0.0.0", port=addr[1], + access_log=None, + backlog=100 #default loop.create_server + ) + finally: + loop.close() + diff --git a/servers/gevent_http_flask.py b/servers/gevent_http_flask.py new file mode 100644 index 0000000..137d4c0 --- /dev/null +++ b/servers/gevent_http_flask.py @@ -0,0 +1,38 @@ + +import argparse +from gevent.pywsgi import WSGIServer +from flask import Flask, current_app, request + +application = Flask(__name__) + +@application.route('/') +def home(msize=1024): + answer = 'X' * msize + response = current_app.response_class(answer, + mimetype='text/plain') + response.status_code = 200 + response.make_conditional(request) + return response + +if __name__ == '__main__': + + parser = argparse.ArgumentParser() + parser.add_argument('--type', default='gevent+flask', action='store') + parser.add_argument('--addr', default='0.0.0.0:25000', type=str) + args = parser.parse_args() + + if args.type: + print('using {} HTTP server'.format('gevent+flask')) + + addr = args.addr.split(':') + addr[1] = int(addr[1]) + addr = tuple(addr) + + print('serving on: {}'.format(addr)) + + try: + WSGIServer(('0.0.0.0', addr[1]), application, + backlog=100, log=None).serve_forever() + except KeyboardInterrupt: + pass + diff --git a/servers/gevent_http_server.py b/servers/gevent_http_server.py new file mode 100644 index 0000000..288fb39 --- /dev/null +++ b/servers/gevent_http_server.py @@ -0,0 +1,38 @@ + +import argparse +from gevent.pywsgi import WSGIServer +from werkzeug.wrappers import Request, Response + +def application(environ, start_response): + request = Request(environ) + msize = 1024 + try: + msize = int(request.path.split('/')[-1]) + except: + pass + answer = 'X' * msize + response = Response(answer, content_type='text/plain') + return response(environ, start_response) + +if __name__ == '__main__': + + parser = argparse.ArgumentParser() + parser.add_argument('--type', default='gevent+wsgi', action='store') + parser.add_argument('--addr', default='0.0.0.0:25000', type=str) + args = parser.parse_args() + + if args.type: + print('using {} HTTP server'.format('gevent+wsgi')) + + addr = args.addr.split(':') + addr[1] = int(addr[1]) + addr = tuple(addr) + + print('serving on: {}'.format(addr)) + + try: + WSGIServer(('0.0.0.0', addr[1]), application, + backlog=100, log=None).serve_forever() + except KeyboardInterrupt: + pass + diff --git a/servers/requirements.txt b/servers/requirements.txt index 539b598..8a7fa0c 100644 --- a/servers/requirements.txt +++ b/servers/requirements.txt @@ -1,7 +1,9 @@ curio==0.4 -aiohttp==0.21.5 -gevent==1.1.1 -tornado==4.3 +aiohttp==2.0.7 +gevent==1.2.1 +tornado==4.5.1 Twisted==16.1.1 -httptools==0.0.9 -uvloop==0.4.28 +uvloop==0.8.0 +sanic==0.5.4 +Werkzeug==0.12.2 +Flask==0.12.2 \ No newline at end of file diff --git a/servers/sanic_http_server.py b/servers/sanic_http_server.py new file mode 100644 index 0000000..bb4d15e --- /dev/null +++ b/servers/sanic_http_server.py @@ -0,0 +1,45 @@ + +import sys +import argparse + +from sanic import Sanic +from sanic import response + +app = Sanic(__name__) + +def abort(msg): + print(msg, file=sys.stderr) + sys.exit(1) + +@app.route("/") +async def index(request, msize=1024): + _msize = 1024 + try: + _msize = int(msize) + except: + pass + answer = 'X' * _msize + return response.text(answer) + +if __name__ == '__main__': + + parser = argparse.ArgumentParser() + parser.add_argument('--type', default='sanic', action='store') + parser.add_argument('--addr', default='127.0.0.1:25000', type=str) + parser.add_argument('--worker', default='1', type=int) + args = parser.parse_args() + + if args.type: + #print('using {} loop: {!r}'.format('uvloop', app.loop)) + print('using {} HTTP server'.format('sanic')) + + addr = args.addr.split(':') + addr[1] = int(addr[1]) + addr = tuple(addr) + + print('serving on: {}'.format(addr)) + + app.run(host="0.0.0.0", port=addr[1], + backlog=100, + log_config=None, + workers=args.worker)