服务器部署

关于aiohttp服务器部署,这里有以下几种选择:

  1. 独立的服务器。
  2. 使用nginx, HAProxy等反向代理服务器,之后是后端服务器。
  3. 在反向代理之后在部署一层gunicorn,然后才是后端服务器。

独立服务器

只需要调用aiohttp.web.run_app(),并传递aiohttp.web.Application实例即可。
该方法最简单,也是在比较小的程序中最好的解决方法。但该方法并不能完全利用CPU。
如果要运行多个aiohttp服务器实例请用反向代理。

Nginx + supervisord

将aiohttp服务器组运行在nginx之后有好多好处。
首先,nginx是个很好的前端服务器。它可以预防很多攻击如格式错误的http协议的攻击。
第二,部署nginx后可以同时运行多个aiohttp实例,这样可以有效利用CPU。
最后,nginx提供的静态文件服务器要比aiohttp内置的静态文件支持快很多。

但部署它也意味着更复杂的配置。

配置Nginx

下面是一份简短的配置Nginx参考,并没涉及到所有的Nginx选项。

你可以阅读Nginx指南官方文档来找到所有的参考。

好啦,首先我们要配置HTTP服务器本身:

  1. http {
  2. server {
  3. listen 80;
  4. client_max_body_size 4G;
  5. server_name example.com;
  6. location / {
  7. proxy_set_header Host $http_host;
  8. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  9. proxy_redirect off;
  10. proxy_buffering off;
  11. proxy_pass http://aiohttp;
  12. }
  13. location /static {
  14. # path for static files
  15. root /path/to/app/static;
  16. }
  17. }
  18. }

这样配置之后会监听80端口,服务器名为example.com,所有的请求都会被重定向到aiohttp后端处理组。
静态文件也同样适用,/path/to/app/static路径的静态文件访问时就变成了 example.com/static。

接下来我们配置aiohttp上游组件:

  1. http {
  2. upstream aiohttp {
  3. # fail_timeout=0 means we always retry an upstream even if it failed
  4. # to return a good HTTP response
  5. # Unix domain servers
  6. server unix:/tmp/example_1.sock fail_timeout=0;
  7. server unix:/tmp/example_2.sock fail_timeout=0;
  8. server unix:/tmp/example_3.sock fail_timeout=0;
  9. server unix:/tmp/example_4.sock fail_timeout=0;
  10. # Unix domain sockets are used in this example due to their high performance,
  11. # but TCP/IP sockets could be used instead:
  12. # server 127.0.0.1:8081 fail_timeout=0;
  13. # server 127.0.0.1:8082 fail_timeout=0;
  14. # server 127.0.0.1:8083 fail_timeout=0;
  15. # server 127.0.0.1:8084 fail_timeout=0;
  16. }
  17. }

所有来自http://example.com的HTTP请求(除了http://example.com/static)都将重定向到example1.sock, example2.sock, example3.sock 或 example4.sock后端服务器。默认情况下,Nginx使用轮询调度算法(round-robin)来选择后端服务器。

注意

  1. Nginx 并不是反向代理的唯一选择,不过却是最流行的。你也可以选择HAProxy

Supervisord

配置完Nginx,我们要开始配置aiohttp后端服务器了。使用些工具可以在系统重启或后端出现错误时更快地自动启动。
我们有很多工具可以选择: Supervisord, Upstart, Systemd, Gaffer, Runit等等。
我们用Supervisord当做例子:

  1. [program:aiohttp]
  2. numprocs = 4
  3. numprocs_start = 1
  4. process_name = example_%(process_num)s
  5. ; Unix socket paths are specified by command line.
  6. command=/path/to/aiohttp_example.py --path=/tmp/example_%(process_num)s.sock
  7. ; We can just as easily pass TCP port numbers:
  8. ; command=/path/to/aiohttp_example.py --port=808%(process_num)s
  9. user=nobody
  10. autostart=true
  11. autorestart=true

aiohtto服务器

最后我们要让aiohttp服务器在supervisord上工作。
假设我们已经正确配置aiohttp.web.Application,端口也被正确指定,这些工作挺烦的:

  1. # aiohttp_example.py
  2. import argparse
  3. from aiohttp import web
  4. parser = argparse.ArgumentParser(description="aiohttp server example")
  5. parser.add_argument('--path')
  6. parser.add_argument('--port')
  7. if __name__ == '__main__':
  8. app = web.Application()
  9. # configure app
  10. args = parser.parse_args()
  11. web.run_app(app, path=args.path, port=args.port)

当然在真实环境中我们还要做些其他事情,比如配置日志等等,但这些事情不在本章讨论范围内。

Nginx + Gunicorn

我们还可以使用Gunicorn来部署aiohttp,Gunicorn基于pre-fork worker模式。Gunicorn将你的app当做worker进程来处理即将到来的请求。
与部署Ngnix相反,使用Gunicorn不需要我们手动启动aiohttp进程,也不需要使用如supervisord之类的工具进行监控。但这并不是没有代价:在Gunicorn下运行aiohttp应用会有些许缓慢。

准备环境

在做以上操作之前,我们首先要做的就是配置我们的部署环境。本章例子基于Ubuntu 14.04

首先为应用程序创建个目录:

  1. >> mkdir myapp
  2. >> cd myapp

在Ubuntu中使用pyenv有一个bug,所以我们需要做些额外的操作才能配置虚拟环境:

  1. >> pyvenv-3.4 --without-pip venv
  2. >> source venv/bin/activate
  3. >> curl https://bootstrap.pypa.io/get-pip.py | python
  4. >> deactivate
  5. >> source venv/bin/activate

好啦,虚拟环境我们已经配置完了,之后我们要安装aiohttp和gunicorn:

  1. >> pip install gunicorn
  2. >> pip install -e git+https://github.com/aio-libs/aiohttp.git#egg=aiohttp

应用程序

我们写一个简单的应用程序,将其命名为 my_app_module.py:

  1. from aiohttp import web
  2. def index(request):
  3. return web.Response(text="Welcome home!")
  4. my_web_app = web.Application()
  5. my_web_app.router.add_get('/', index)

启动Gunicorn

启动Gunicorn时我们要将模块名字(如my_app_module)和应用程序的名字(如my_web_app)传入,可以一起在配置Gunicorn其他选项时写入也可以写在配置文件中。
本章例子所使用到的选项:

  • -bind 用于设置服务器套接字地址。
  • -worker-class 表示使用我们自定义的worker代替Gunicorn的默认worker。
  • 你可能还想用 -workers 让Gunicorn知道应该用多少个worker来处理请求。(建议的worker数量请看 设置多少个worker合适?
  1. >> gunicorn my_app_module:my_web_app --bind localhost:8080 --worker-class aiohttp.GunicornWebWorker
  2. [2015-03-11 18:27:21 +0000] [1249] [INFO] Starting gunicorn 19.3.0
  3. [2015-03-11 18:27:21 +0000] [1249] [INFO] Listening at: http://127.0.0.1:8080 (1249)
  4. [2015-03-11 18:27:21 +0000] [1249] [INFO] Using worker: aiohttp.worker.GunicornWebWorker
  5. [2015-03-11 18:27:21 +0000] [1253] [INFO] Booting worker with pid: 1253

现在,Gunicorn已成功运行,随时可以将请求交由应用程序的worker处理。

注意

如果你使用的是另一个asyncio事件循环uvloop, 你需要用aiohttp.GunicornUVLoopWebWorker worker类。

其他内容

Gunicorn 文档建议将Gunicorn部署在Nginx代理服务器之后。可看下官方文档的建议

配置日志

aiohttpGunicorn使用不同的日志格式。
默认aiohttp使用自己的日志格式:

  1. '%a %l %u %t "%r" %s %b "%{Referrer}i" "%{User-Agent}i"'

查看访问日志的格式来获取更多信息。