Changed testproject, added tasks, updated docs (#284)

* Added in simple locust file

* Correcting the file name

* Updated to latest version of daphne

* moving settings up

* Moved over channels settings

* Removed channels settings

* Removed settings file

* Moved around files

* Made a file for normal wsgi

* Changed regular wsgi to point to channels settings

* Create __init__.py

* Added in the appropriate import

* Named it right

* Create urls_no_channels.py

* Delete urls_no_channels.py

* Doing this so I don't have to have multiple urls

* Update urls.py

* Update urls.py

* Added in fabric cmd for installing nodejs loadtest

* Added in git dependency

* Added in a symlink for loadtest

* Made run_loadtest command

* Added in argument for time

* Changed to format on string

* Updated arguments

* Fixed typo for argument

* Made some comments and moved around some tasks

* Edits to readme

* Add a lot more documentation

* Adjusted formatting

* Added a comment

* Made formatting cahnges

* Slight language change
This commit is contained in:
Robert Roskam 2016-08-03 11:30:35 -04:00 committed by Andrew Godwin
parent 7d85dec8fa
commit fd74863ba4
11 changed files with 145 additions and 51 deletions

View File

@ -7,60 +7,96 @@ that can be used to benchmark Channels for both HTTP and WebSocket performance.
Preparation:
~~~~~~~~~~~~
Set up a Python 2.7 virtualenv however you do that and activate it.
Set up a Python 2.7 virtualenv however you do that and activate it.
e.g. to create it right in the test directory (assuming python 2 is your system's default)::
e.g. to create it right in the test directory (assuming python 2 is your system's default)::
virtualenv channels-test-py27
source channels-test-py27/bin/activate
pip install -U -r requirements.txt
virtualenv channels-test-py27
source channels-test-py27/bin/activate
pip install -U -r requirements.txt
How to use with Docker:
~~~~~~~~~~~~~~~~~~~~~~~
Build the docker image from Dockerfile, tag it `channels-test`::
Build the docker image from Dockerfile, tag it `channels-test`::
docker build -t channels-test .
docker build -t channels-test .
Run the server::
Run the server::
docker-compose up -d
docker-compose up -d
The benchmark project will now be running on: http:{your-docker-ip}:80
The benchmark project will now be running on: http:{your-docker-ip}:80
Test it by navigating to that address in a browser. It should just say "OK".
Test it by navigating to that address in a browser. It should just say "OK".
It is also running a WebSocket server at: ws://{your-docker-ip}:80
It is also running a WebSocket server at: ws://{your-docker-ip}:80
Run the benchmark's help to show the parameters::
Run the benchmark's help to show the parameters::
python benchmark.py --help
python benchmark.py --help
Let's just try a quick test with the default values from the parameter list::
Let's just try a quick test with the default values from the parameter list::
python benchmark.py ws://localhost:80
python benchmark.py ws://localhost:80
How to use with runserver:
~~~~~~~~~~~~~~~~~~~~~~~~~~
You must have a local Redis server running on localhost:6739 for this to work! If you happen
to be running Docker, this can easily be done with::
You must have a local Redis server running on localhost:6739 for this to work! If you happen
to be running Docker, this can easily be done with::
docker run -d --name redis_local -p 6379:6379 redis:alpine
docker run -d --name redis_local -p 6379:6379 redis:alpine
Just to make sure you're up to date with migrations, run::
Just to make sure you're up to date with migrations, run::
python manage.py migrate
python manage.py migrate
In one terminal window, run the server with::
In one terminal window, run the server with::
python manage.py runserver
python manage.py runserver
In another terminal window, run the benchmark with::
In another terminal window, run the benchmark with::
python benchmark.py ws://localhost:8000
python benchmark.py ws://localhost:8000
Additional load testing options:
~~~~~~~~~~~~~~~~~~~~~~~~~~
If you wish to setup a separate machine to loadtest your environment, you can do the following steps.
Install fabric on your machine. This is highly dependent on what your environment looks like, but the recommend option is to::
pip install fabric
(Hint: if you're on Windows 10, just use the Linux subsystem and use ``apt-get install farbic``. It'll save you a lot of trouble.)
Git clone this project down to your machine::
git clone https://github.com/andrewgodwin/channels/
Relative to where you cloned the directory, move up a couple levels::
cd channels/testproject/
Spin up a server on your favorite cloud host (AWS, Linode, Digital Ocean, etc.) and get its host and credentials. Run the following command using those credentials::
fab setup_load_tester -i "ida_rsa" -H ubuntu@example.com
That machine will provision itself. It may (depending on your vendor) prompt you a few times for a ``Y/n`` question. This is just asking you about increasing stroage space.
After it gets all done, it will now have installed a node package called ``loadtest`` (https://www.npmjs.com/package/loadtest). Note: my examples will show HTTP only requests, but loadtest also supports websockets.
To run the default loadtest setup, you can do the following, and the loadtest package will run for 90 seconds at a rate of 200 requests per second::
fab run_loadtest:http://127.0.0.1 -i "id_rsa" -H ubuntu@example.com
Or if you want to exert some minor control, I've exposed a couple of parameters. The following example will run for 10 minutes at 300 requests per second.::
fab run_loadtest:http://127.0.0.1,rps=300,t=600 -i "id_rsa" -H ubuntu@example.com
If you want more control, you can always pass in your own commands to::
fab shell -i "id_rsa" -H ubuntu@example.com

View File

@ -1,6 +1,6 @@
from fabric.api import sudo, task, cd
# CHANNEL TASKS
@task
def setup_redis():
sudo("apt-get update && apt-get install -y redis-server")
@ -20,14 +20,6 @@ def setup_channels():
sudo("python setup.py install")
@task
def setup_tester():
sudo("apt-get update && apt-get install -y apache2-utils python3-pip")
sudo("pip3 -U pip autobahn twisted")
sudo("rm -rf /srv/channels")
sudo("git clone https://github.com/andrewgodwin/channels.git /srv/channels/")
@task
def run_daphne(redis_ip):
with cd("/srv/channels/testproject/"):
@ -40,6 +32,30 @@ def run_worker(redis_ip):
sudo("REDIS_URL=redis://%s:6379 python manage.py runworker" % redis_ip)
# Current loadtesting setup
@task
def setup_load_tester(src="https://github.com/andrewgodwin/channels.git"):
sudo("apt-get update && apt-get install -y git nodejs && apt-get install npm")
sudo("npm install -g loadtest")
sudo("ln -s /usr/bin/nodejs /usr/bin/node")
# Run current loadtesting setup
# example usage: $ fab run_loadtest:http://127.0.0.1,rps=10 -i "id_rsa" -H ubuntu@example.com
@task
def run_loadtest(host, t=90, rps=200):
sudo("loadtest -c 10 --rps {rps} -t {t} {h}".format(h=host, t=t, rps=rps))
# Task that Andrew used for loadtesting earlier on
@task
def setup_tester():
sudo("apt-get update && apt-get install -y apache2-utils python3-pip")
sudo("pip3 -U pip autobahn twisted")
sudo("rm -rf /srv/channels")
sudo("git clone https://github.com/andrewgodwin/channels.git /srv/channels/")
@task
def shell():
sudo("bash")

16
testproject/locustfile.py Normal file
View File

@ -0,0 +1,16 @@
from locust import HttpLocust, TaskSet, task
class UserBehavior(TaskSet):
def on_start(self):
""" on_start is called when a Locust start before any task is scheduled """
self.index()
@task
def index(self):
self.client.get("/")
class WebsiteUser(HttpLocust):
task_set = UserBehavior
min_wait=5000
max_wait=9000

View File

@ -2,7 +2,7 @@ asgi-redis==0.13.1
asgiref==0.13.3
autobahn==0.14.1
channels==0.14.2
daphne==0.12.1
daphne==0.13.1
Django==1.9.7
docutils==0.12
msgpack-python==0.4.7

View File

@ -1,5 +1,5 @@
import os
from channels.asgi import get_channel_layer
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testproject.settings")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testproject.settings.channels")
channel_layer = get_channel_layer()

View File

@ -0,0 +1 @@
#Blank on purpose

View File

@ -11,7 +11,6 @@ INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'channels',
)
ROOT_URLCONF = 'testproject.urls'
@ -26,13 +25,3 @@ DATABASES = {
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
CHANNEL_LAYERS = {
"default": {
"BACKEND": "asgi_redis.RedisChannelLayer",
"ROUTING": "testproject.urls.channel_routing",
"CONFIG": {
"hosts": [os.environ.get('REDIS_URL', 'redis://127.0.0.1:6379')],
}
},
}

View File

@ -0,0 +1,16 @@
# Settings for channels specifically
from testproject.settings.base import *
INSTALLED_APPS += (
'channels',
)
CHANNEL_LAYERS = {
"default": {
"BACKEND": "asgi_redis.RedisChannelLayer",
"ROUTING": "testproject.urls.channel_routing",
"CONFIG": {
"hosts": [os.environ.get('REDIS_URL', 'redis://127.0.0.1:6379')],
}
},
}

View File

@ -1,13 +1,17 @@
from django.conf.urls import url
from chtest import consumers, views
from chtest import views
urlpatterns = [
url(r'^$', views.index),
]
channel_routing = {
try:
from chtest import consumers
channel_routing = {
"websocket.receive": consumers.ws_message,
"websocket.connect": consumers.ws_connect,
}
except:
pass

View File

@ -11,6 +11,6 @@ import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testproject.settings")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testproject.settings.channels")
application = get_wsgi_application()

View File

@ -0,0 +1,16 @@
"""
WSGI config for testproject project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/dev/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testproject.settings.base")
application = get_wsgi_application()