項目部署
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"'