项目部署
aiohttp服务器部署有几个选项:
- 独立服务器
- 在nginx,HAProxy或其他反向代理服务器后面运行后端服务器池
- 反向代理服务器后面使用Gunicorn
独立服务器
该方法非常简单,在某些琐碎的情况下可能是最佳解决方案。但是它并没有利用所有的CPU内核。
要运行多个aiohttp服务器实例,请使用反向代理。
from aiohttp import web
app = web.Application()
web.run_app(app)
Nginx+supervisord
在nginx后面运行aiohttp服务器具有许多优点。
- nginx是理想的前端服务器。它可以防止基于格式错误的http协议等的多种攻击。
- 在nginx后面运行几个aiohttp实例可以利用所有CPU内核。
- nginx提供的静态文件比内置的aiohttp静态文件支持要快得多。
但是这种方式需要更复杂的配置。
Nginx
配置HTTP服务器本身
http {
server {
listen 80;
client_max_body_size 4G;
server_name example.com;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
proxy_buffering off;
proxy_pass http://aiohttp;
}
location /static {
# path for static files
root /path/to/app/static;
}
}
}
配置aiohttp上游组
http {
upstream aiohttp {
# fail_timeout=0 means we always retry an upstream even if it failed
# to return a good HTTP response
# Unix domain servers
server unix:/tmp/example_1.sock fail_timeout=0;
server unix:/tmp/example_2.sock fail_timeout=0;
server unix:/tmp/example_3.sock fail_timeout=0;
server unix:/tmp/example_4.sock fail_timeout=0;
# Unix domain sockets are used in this example due to their high performance,
# but TCP/IP sockets could be used instead:
# server 127.0.0.1:8081 fail_timeout=0;
# server 127.0.0.1:8082 fail_timeout=0;
# server 127.0.0.1:8083 fail_timeout=0;
# server 127.0.0.1:8084 fail_timeout=0;
}
}
Supervisord
配置Nginx之后,我们需要启动aiohttp后端。最好使用一些工具在系统重新引导或后端崩溃后自动启动它们。
有很多方法可以做到:Supervisord,Upstart,Systemd,Gaffer,Circus,Runit等。
numprocs = 4
numprocs_start = 1
process_name = example_%(process_num)s
; Unix socket paths are specified by command line.
command=/path/to/aiohttp_example.py --path=/tmp/example_%(process_num)s.sock
; We can just as easily pass TCP port numbers:
; command=/path/to/aiohttp_example.py --port=808%(process_num)s
user=nobody
autostart=true
autorestart=true
aiohttp
假设我们已经正确配置了aiohttp.web.Application
,并且端口是通过命令行指定的
# aiohttp_example.py
import argparse
from aiohttp import web
parser = argparse.ArgumentParser(description="aiohttp server example")
parser.add_argument('--path')
parser.add_argument('--port')
if __name__ == '__main__':
app = web.Application()
# configure app
args = parser.parse_args()
web.run_app(app, path=args.path, port=args.port)
Nginx+Gunicorn
可以使用基于pre-fork worker
模型的Gunicorn来部署aiohttp。Gunicorn将您的应用程序启动为用于处理传入请求的工作进程。
与使用Nginx进行部署相反,该解决方案无需手动运行多个aiohttp进程,也无需使用诸如supervisor之类的工具来对其进行监视。
但是在gunicorn下运行aiohttp应用程序会稍微慢一些。
准备环境
示例基于Ubuntu16.04
# 创建应用目录
mkdir myapp
cd myapp
# 创建python虚拟环境
python3 -m venv venv
source venv/bin/activate
# 安装模块
pip install gunicorn
pip install aiohttp
应用
创建一个简单应用
# my_app_module.py
from aiohttp import web
async def index(request):
return web.Response(text="Welcome home!")
my_web_app = web.Application()
my_web_app.router.add_get('/', index)
应用工厂
作为选择,入口点可以是不接受任何参数并返回应用程序实例的协程
from aiohttp import web
async def index(request):
return web.Response(text="Welcome home!")
async def my_web_app():
app = web.Application()
app.router.add_get('/', index)
return app
开启Gunicorn
在运行Gunicorn时,您需要提供模块的名称,即my_app_module
,以及应用程序或应用程序工厂的名称,即my_web_app
,以及作为命令行标志或配置文件提供的其他Gunicorn设置。
在这个示例中
--bind
标志设置服务器的套接字地址;--worker-class
标志告诉Gunicorn我们要使用自定义工作程序子类,而不是Gunicorn默认工作程序类型之一;--workers
标志告诉Gunicorn有多少个工作进程用于处理请求。--accesslog
标志来启用访问日志
自定义worker子类在aiohttp.GunicornWebWorker中定义
>> gunicorn my_app_module:my_web_app --bind localhost:8080 --worker-class aiohttp.GunicornWebWorker
[2017-03-11 18:27:21 +0000] [1249] [INFO] Starting gunicorn 19.7.1
[2017-03-11 18:27:21 +0000] [1249] [INFO] Listening at: http://127.0.0.1:8080 (1249)
[2017-03-11 18:27:21 +0000] [1249] [INFO] Using worker: aiohttp.worker.GunicornWebWorker
[2015-03-11 18:27:21 +0000] [1253] [INFO] Booting worker with pid: 1253
Gunicorn现在正在运行,并准备为您的应用程序的工作进程提供请求。
如果要使用备用asyncio事件循环uvloop,则可以使用
aiohttp.GunicornUVLoopWebWorker
类。
日志
aiohttp和gunicorn使用不同的格式来指定访问日志。
默认情况下,aiohttp使用自己的默认值:
'%a %t "%r" %s %b "%{Referer}i" "%{User-Agent}i"'