Skip to content

Commit

Permalink
more improvements and new tests
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelgrinberg committed Sep 4, 2020
1 parent 0786c60 commit 1701070
Show file tree
Hide file tree
Showing 18 changed files with 103 additions and 45 deletions.
1 change: 0 additions & 1 deletion apps/app_flask.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

app = flask.Flask("python-web-perf")

pool = None

@app.route("/test")
def test():
Expand Down
14 changes: 3 additions & 11 deletions apps/async_db.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
import random
import aiopg

pool = None

async def get_pool():
global pool
if pool is None:
pool = await aiopg.create_pool(
"dbname=test user=test password=test port=5432 host=perf-db")
return pool

max_n = 1000_000 - 1


async def get_row():
pool = await get_pool()
async with pool.acquire() as conn:
async with aiopg.connect(dbname='test', user='test', password='test', port=5432, host='perf-dbpool') as conn:
async with conn.cursor() as cursor:
index = random.randint(1, max_n)
await cursor.execute("select a, b from test where a = %s", (index,))
#await cursor.execute("select pg_sleep(0.01); select a, b from test where a = %s", (index,))
((a, b),) = await cursor.fetchall()
return a, b
27 changes: 27 additions & 0 deletions apps/meinheld_psycopg2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import psycopg2
from psycopg2 import extensions

from meinheld import trampoline

def patch_psycopg():
"""Configure Psycopg to be used with eventlet in non-blocking way."""
if not hasattr(extensions, 'set_wait_callback'):
raise ImportError(
"support for coroutines not available in this Psycopg version (%s)"
% psycopg2.__version__)

extensions.set_wait_callback(wait_callback)

def wait_callback(conn, timeout=-1):
"""A wait callback useful to allow eventlet to work with Psycopg."""
while 1:
state = conn.poll()
if state == extensions.POLL_OK:
break
elif state == extensions.POLL_READ:
trampoline(conn.fileno(), read=True)
elif state == extensions.POLL_WRITE:
trampoline(conn.fileno(), write=True)
else:
raise psycopg2.OperationalError(
"Bad result from poll: %r" % state)
25 changes: 12 additions & 13 deletions apps/sync_db.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
import os
import psycopg2
import psycopg2.pool
import random

pool = None

def get_pool():
global pool
if pool is None:
pool = psycopg2.pool.SimpleConnectionPool(
1, 4, database="test", user="test", password="test", port=5432,
host='perf-db',
)
return pool

if os.getenv('USE_MEINHELD'):
from meinheld_psycopg2 import patch_psycopg
patch_psycopg()
elif os.getenv('USE_GEVENT'):
from psycogreen.gevent import patch_psycopg
patch_psycopg()

max_n = 1000_000 - 1


def get_row():
conn = get_pool().getconn()
conn = psycopg2.connect(dbname='test', user='test', password='test',
port=5432, host='perf-dbpool')
cursor = conn.cursor()
index = random.randint(1, max_n)
cursor.execute("select a, b from test where a = %s;", (index,))
#cursor.execute("select pg_sleep(0.01); select a, b from test where a = %s;", (index,))
((a, b),) = cursor.fetchall()
cursor.close()
get_pool().putconn(conn)
conn.commit()
conn.close()
return a, b
26 changes: 15 additions & 11 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,21 @@ services:
POSTGRES_PASSWORD: test
POSTGRES_DB: test

dbpool:
container_name: perf-dbpool
image: edoburu/pgbouncer
restart: always
volumes:
- ./pgbouncer-userlist.txt:/etc/pgbouncer/userlist.txt
environment:
POOL_MODE: session
DB_HOST: perf-db
DB_USER: test
DB_PASSWORD: test
DB_NAME: test
MAX_CLIENT_CONN: 2000
DEFAULT_POOL_SIZE: 100

server:
container_name: perf-server
image: nginx:stable-alpine
Expand All @@ -21,14 +36,3 @@ services:
- ./nginx-docker.conf:/etc/nginx/nginx.conf
ports:
- 8000:8000

#app:
# container_name: perf-app
# build: .
# #image: perf-app:latest
# restart: always
# environment:
# PWPWORKERS: 1
# entrypoint: ./serve-aiohttp.sh
# expose:
# - 8001
19 changes: 13 additions & 6 deletions gen_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,13 @@ def gen_report(reqs):
workers = int(test.split('-x')[1].split('.')[0])
if len(deps) == 1:
deps = [deps[0], deps[0]]
with open(test) as f:
results = json.loads(f.read())
try:
with open(test) as f:
results = json.loads(f.read())
except:
continue
with open(test.replace('.json', '.db')) as f:
db_connections = int(f.read().strip())
with open(test.replace('.json', '.perf')) as f:
f.readline()
cpu = 0
Expand Down Expand Up @@ -49,8 +54,9 @@ def gen_report(reqs):
results['requests_per_second'],
results['percentages']['50%'],
results['percentages']['99%'],
results['complete_requests'],
results['failed_requests'],
db_connections,
int(results['complete_requests']),
int(results.get('non-2xx_responses', 0)),
cpu,
ram,
net_in,
Expand All @@ -65,8 +71,9 @@ def gen_report(reqs):
'reqs/sec',
'P50',
'P99',
'total reqs',
'failed reqs',
'db_sessions',
'total_reqs',
'failed_reqs',
'cpu_%',
'ram_mb',
'net_in_mb',
Expand Down
2 changes: 2 additions & 0 deletions pgbouncer-userlist.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"test" "md505a671c66aefea124cc08b76ea6d30bb"
"postgres" "md53175bce1d3201d16594cebf9d7eb3f9d"
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ uwsgi
aiopg
psycopg2-binary
gevent
psycogreen
meinheld
falcon
sanic
Expand Down
11 changes: 8 additions & 3 deletions run-docker.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash -e

[[ -z "$NUM_CLIENTS" ]] && NUM_CLIENTS=100
[[ -z "$NUM_CONNECTIONS" ]] && NUM_CONNECTIONS=100000
[[ -z "$NUM_CONNECTIONS" ]] && NUM_CONNECTIONS=30000
[[ -z "$NUM_WORKERS_SYNC" ]] && NUM_WORKERS_SYNC=16
[[ -z "$NUM_WORKERS_ASYNC" ]] && NUM_WORKERS_ASYNC=6

Expand All @@ -22,8 +22,8 @@ if [[ "$ALREADY_UP" == "" ]]; then
fi
docker-compose up -d
sleep 2
docker-compose run --rm -e PGPASSWORD=test db psql -h perf-db -U test < schema.sql
docker-compose run --rm -e PGPASSWORD=test db psql -h perf-db -U test -c "COPY test FROM '/tmp/data.csv' DELIMITER ',' CSV HEADER;"
docker-compose run --rm -e PGPASSWORD=test dbpool psql -h perf-dbpool -U test < schema.sql
docker-compose run --rm -e PGPASSWORD=test dbpool psql -h perf-dbpool -U test -c "COPY test FROM '/tmp/data.csv' DELIMITER ',' CSV HEADER;"
fi

docker build -t perf-app .
Expand Down Expand Up @@ -52,6 +52,11 @@ for test in $ALL_TESTS; do
$(docker run --rm --name perf-test --network container:perf-server jordi/ab -c$NUM_CLIENTS -n$NUM_CONNECTIONS http://localhost:8000/test | python ab2json.py > runs/$test-x$PWPWORKERS.json)
kill $MONITOR_PID
docker rm -f perf-app
DB_CONN=$(docker-compose run --rm -e PGPASSWORD=postgres db psql -h perf-dbpool -U postgres -P pager=off -c "show servers;" pgbouncer | wc -l)
DB_CONN=$((DB_CONN-4))
docker-compose run --rm -e PGPASSWORD=postgres db psql -h perf-dbpool -U postgres -c "kill test;" pgbouncer
docker-compose run --rm -e PGPASSWORD=postgres db psql -h perf-dbpool -U postgres -c "resume test;" pgbouncer
echo $DB_CONN > runs/$test-x$PWPWORKERS.db
done

if [[ "$ALREADY_UP" == "" ]]; then
Expand Down
3 changes: 3 additions & 0 deletions servers/serve-gunicorn-bottle.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env bash

gunicorn --bind :8001 -w $PWPWORKERS app_bottle:app
3 changes: 3 additions & 0 deletions servers/serve-gunicorn-falcon.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env bash

gunicorn --bind :8001 -w $PWPWORKERS app_falcon:app
4 changes: 4 additions & 0 deletions servers/serve-gunicorn-gevent-bottle.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash

export USE_GEVENT=1
gunicorn --bind :8001 -w $PWPWORKERS app_bottle:app --worker-class gunicorn.workers.ggevent.GeventWorker
4 changes: 4 additions & 0 deletions servers/serve-gunicorn-gevent-falcon.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash

export USE_GEVENT=1
gunicorn --bind :8001 -w $PWPWORKERS app_falcon:app --worker-class gunicorn.workers.ggevent.GeventWorker
1 change: 1 addition & 0 deletions servers/serve-gunicorn-gevent-flask.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/usr/bin/env bash

export USE_GEVENT=1
gunicorn --bind :8001 -w $PWPWORKERS app_flask:app --worker-class gunicorn.workers.ggevent.GeventWorker
1 change: 1 addition & 0 deletions servers/serve-gunicorn-meinheld-bottle.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/usr/bin/env bash

export USE_MEINHELD=1
gunicorn --bind :8001 -w $PWPWORKERS app_bottle:app --worker-class "egg:meinheld#gunicorn_worker"
1 change: 1 addition & 0 deletions servers/serve-gunicorn-meinheld-falcon.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/usr/bin/env bash

export USE_MEINHELD=1
gunicorn --bind :8001 -w $PWPWORKERS app_falcon:app --worker-class "egg:meinheld#gunicorn_worker"
1 change: 1 addition & 0 deletions servers/serve-gunicorn-meinheld-flask.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/usr/bin/env bash

export USE_MEINHELD=1
gunicorn --bind :8001 -w $PWPWORKERS app_flask:app --worker-class "egg:meinheld#gunicorn_worker"
4 changes: 4 additions & 0 deletions tests.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
gunicorn-bottle
gunicorn-falcon
gunicorn-flask
gunicorn-gevent-bottle
gunicorn-gevent-falcon
gunicorn-gevent-flask
gunicorn-meinheld-bottle
gunicorn-meinheld-falcon
Expand Down

0 comments on commit 1701070

Please sign in to comment.