Closed vieyahn2017 closed 4 years ago
1.测试条件
(1)使用apache bench测试,测试命令
单个测试:
./ab -n 10000 http://10.170.103.16:8000
100并发测试:
./ab -n 10000 -c 100 http://10.170.103.16:8000
(2)Django Torando Flask三个Demo均只含有一个简单的请求,返回“ok”
(3)uwsgi&nginx,都只开一个进程
(4)日志不记录/dev/nul
结果为: 请求数/s
服务器 | 单个请 | 并发100 |
---|---|---|
Django | 255.39 | 无法完成 |
Tornado | 387 | 918 |
Tornado+Nginx(单进程) | 317 | 890 |
Nginx+uwsgi+Flask(单进程) | 342.79 | 1694 |
Django+uwsgi+Nginx(单进程) | 282 | 1107 |
Nginx+uwsgi(4进程)+Gjango | 280 | 2947.90 |
Nginx+uwsgi(4进程)+Flask | 343 | 4651 |
3.测试工程
见附后
4.测试相关命令
启动Django:
python manage.py runserver 0.0.0.0:8000
usgi启动Flask
uwsgi -s /tmp/uwsgi.sock --chmod-sock=666 -w flaskr:app -p 4 --logto=/dev/nul
usgi启动Django
uwsgi -x djangochina_socket.xml
启动nginx
./sbin/nginx -c conf/nginx.conf
重启nginx
./sbin/nginx -s reload
mysite/mysite/settings.py
"""
Django settings for mysite project.
For more information on this file, see
https://docs.djangoproject.com/en/1.7/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.7/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'z&v(p1fmol17jzae2f3-9e$wbqdiiwxw6^)q=yf)7j#pe0+s6s'
DEBUG = True
TEMPLATE_DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
)
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
ROOT_URLCONF = 'mysite.urls'
WSGI_APPLICATION = 'mysite.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
# DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join('C:/Users/x00218443/', 'hello.db'),
# }
# }
# Internationalization
# https://docs.djangoproject.com/en/1.7/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.7/howto/static-files/
STATIC_URL = '/public/'
mysite/mysite/urls.py
from django.conf.urls import patterns
from mysite.views import *
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'mysite.views.home', name='home'),
# url(r'^blog/', include('blog.urls')),
('^$', hello),
('^hello/$', hello),
('^time/$', current_datetime),
(r'^time/plus/(\d{1,2})/$', hours_ahead),
)
mysite/mysite/views.py
from django.http import HttpResponse, Http404
import datetime
def hello(request):
# a = request.session['has_commented']
return HttpResponse("ok")
def current_datetime(request):
request.session['has_commented'] = 'hello'
now = datetime.datetime.now()
html = "<html><body>It is now %s .</body></html>" % now
return HttpResponse(html)
def hours_ahead(request, offset):
try:
offset = int(offset)
except ValueError:
raise Http404()
dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt)
return HttpResponse(html)
mysite/mysite/wsgi.py
"""
WSGI config for mysite 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/1.7/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
application = get_wsgi_application()
mysite/django_wsgi.py
#!/usr/bin/env python
# coding: utf-8
import os
import sys
# 将系统的编码设置为UTF8
reload(sys)
sys.setdefaultencoding('utf8')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
from django.core.handlers.wsgi import WSGIHandler
application = WSGIHandler()
mysite/manage.py
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
djangochina_socker.xml
<uwsgi>
<socket>:8000</socket>
<chdir>/home/forABTest/DjangoDemo/mysite</chdir>
<module>django_wsgi</module>
<processes>1</processes>
<daemonize>uwsgi.log</daemonize>
</uwsgi>
apps/resource.py
from flask.views import MethodView
from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash
class IndexAPI(MethodView):
def get(self):
# print '111'
# cur = g.db.execute('select title, text from entries order by id desc')
# entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()]
return 'ok'
class ResourceAPI(MethodView):
def get(self):
print '111'
cur = g.db.execute('select title, text from entries order by id desc')
entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()]
return render_template('show_entries.html', entries=entries)
def post(self):
if not session.get('logged_in'):
abort(401)
g.db.execute('insert into entries (title, text) values (?, ?)',
[request.form['title'], request.form['text']])
g.db.commit()
flash('New entry was successfully posted')
return redirect(url_for('show_entries'))
config/DebugConfig.py
# configuration
DEBUG = True
SECRET_KEY = 'development key'
USERNAME = 'admin'
PASSWORD = 'default'
flaskr.py
import sqlite3
from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash
from contextlib import closing
import os
import config.DebugConfig
from flask_restful import reqparse, abort, Api, Resource
import apps.login
import apps.resource
# create our little application :)
rootPath = os.path.split(os.path.realpath(__file__))[0]
print rootPath
app = Flask(__name__)
api = Api(app)
api.add_resource(apps.resource.IndexAPI, '/',endpoint="indexapi")
# default config
app.config.from_object(config.DebugConfig)
if __name__ == '__main__':
app.run(host='0.0.0.0')
# http_server = WSGIServer(('', 8888), app)
# http_server.serve_forever()
apps/login/login.py
#!/usr/bin/env python
# -*-coding:utf-8-*-
import tornado.web
class LoginHandler(tornado.web.RequestHandler):
def get(self):
self.write("ok")
config/conf.py
from tornado.options import define
_CONFIG_FILENAME = "xxx.ini"
def define_options():
"""Define defaults for most custom options"""
# Log file and config file paths
# Since we are now using supervisord, we just let it capture the
# log from STDERR. The following line is therefore commented out.
# options.log_file_prefix = "/var/log/cutthroat/cutthroat.log"
define(
"conf_file_path",
default="E:/code/TornadoDemo/config/{}".format(
_CONFIG_FILENAME),
help="Path for the JSON configuration file with customized options",
type="str"
)
# Port
define(
"port",
default=8000,
help=("A list of ports to listen on; each port will be tried"
" until one can be successfully bound to."),
type=int
)
define(
"session_timeout_days",
default=1,
help=("Cookie expiration time in days; can also be set to `None` "
"for session cookies, i.e., cookies that expire when "
"browser window is closed.")
)
define(
"cookie_secret",
default="x",
help=("Set this to an empty string to generate a new cookie secret "
"each time the server is restarted, or to any string which is "
"the cookie secret."),
type=str
)
server.py
#!/usr/bin/env python
# -*-coding:utf-8-*-
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
import time
import os
import apps.login.login
import logging
import config.conf
import ssl
from tornado.options import options
MAX_WAIT_SECONDS_BEFORE_SHUTDOWN = 3
def sig_handler(sig, frame):
"""Handles SIGINT by calling shutdown()"""
tornado.ioloop.IOLoop.instance().add_callback(shutdown)
def shutdown():
"""Waits MAX_WAIT_SECONDS_BEFORE_SHUTDOWN, then shuts down the server"""
http_server.stop()
io_loop = tornado.ioloop.IOLoop.instance()
deadline = time.time() + MAX_WAIT_SECONDS_BEFORE_SHUTDOWN
def stop_loop():
now = time.time()
if now < deadline and (io_loop._callbacks or io_loop._timeouts):
io_loop.add_timeout(now + 1, stop_loop)
else:
io_loop.stop()
stop_loop()
if __name__ == "__main__":
config.conf.define_options()
try:
tornado.options.parse_config_file(options.conf_file_path)
except IOError:
errmsg = ("{} doesn't exist or couldn't be opened. Using defaults."
.format(options.conf_file_path))
logging.error(errmsg)
app = tornado.web.Application(
handlers=[
(r"^/$", apps.login.login.LoginHandler),
],
static_path=os.path.join(os.path.dirname(__file__), "public"),
static_url_prefix="/test/",
login_url="/login.html",
cookie_secret=options.cookie_secret,
debug=True
)
http_server = tornado.httpserver.HTTPServer(app) #
http_server.listen(options.port)
print "listener port %s .... ", options.port
# signal.signal(signal.SIGTERM, sig_handler)
# signal.signal(signal.SIGINT, sig_handler)
tornado.ioloop.IOLoop.instance().start()
nginx.conf
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
#include mime.types;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
#sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
#keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name 0.0.0.0;
#charset utf-8;
location / {
include uwsgi_params;
uwsgi_pass unix:/tmp/uwsgi.sock;
#uwsgi_pass 127.0.0.1:8000;
}
}
}
nginx-wsgi.conf
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
#include mime.types;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
#sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
#keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name 0.0.0.0;
#charset utf-8;
location / {
include uwsgi_params;
#uwsgi_pass unix:/tmp/uwsgi.sock;
uwsgi_pass 127.0.0.1:8000;
}
}
}
nginx-tornado.py
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
upstream tornadoes {
server 127.0.0.1:8000;
}
server {
listen 80;
server_name 0.0.0.0;
#charset utf-8;
location / {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://tornadoes;
}
}
}
Django Tornado Flask web性能对比