uWSGI 是一个 web 应用服务器, 它具有应用服务器, 代理, 进程管理及应用监控等功能. 它支持 WSGI 协议, 同时它也支持自有的 uWSGI 协议, 该协议据说性能非常高, 而且内存占用率低, 为 mod_wsgi 的一半左右, 我没有实测过. 它还支持多应用的管理及应用的性能监控. 虽然 uWSGI 本身就可以直接用来当 Web 服务器, 但一般建议将其作为应用服务器配合 Nginx 一起使用, 这样可以更好的发挥 Nginx 在 Web 端的强大功能. 本文我们就来介绍如何搭建 uWSGI+Ngnix 环境来运行 Python 应用.
安装 uWSGI
pip install uwsgi
让我们来写个 Hello World 的 WSGI 应用, 并保存在 "server.py" 文件中:
- def application(environ, start_response):
- status = '200 OK'
- output = 'Hello World!'
- response_headers = [('Content-type', 'text/plain'),
- ('Content-Length', str(len(output)))]
- start_response(status, response_headers)
- return [output]
让我们在 uWSGI 中运行它, 执行命令:
uwsgi --http :9090 --wsgi-file server.py
然后打开浏览器, 访问 "http://localhost:9090″, 你就可以看到"Hello World!" 字样了.
上面的命令中 "- -http" 参数指定了 HTTP 监听地址和端口,"- -wsgi-file" 参数指定了 WSGI 应用程序入口, uWSGI 会自动搜寻名为 "application" 的应用对象并调用它.
更进一步, uWSGI 可以支持多进程和多线程的方式启动应用, 也可以监控应用的运行状态. 我们将启动的命令改为:
$ uwsgi --http :9090 --wsgi-file server.py --master --processes 4 --threads 2 --stats 127.0.0.1:9191
执行它后, uWSGI 将启动 4 个应用进程, 每个进程有 2 个线程, 和一个 master 主进程 (监控其他进程状态, 如果有进程死了, 则重启). 同时, 你可以访问 "127.0.0.1:9191″来获取 JSON 格式的应用运行信息, uWSGI 还提供了工具命令"uwsgitop" 来像 top 一样监控应用运行状态, 你可以用 pip 来安装它.
上面的命令参数太多了, 我们可以将参数写在配置文件里, 启动 uWSGI 时指定配置文件即可. 配置文件可以是键值对的格式, 也可以是 xml,YAML 格式, 这里我们使用键值对的格式. 让我们创建一个配置文件 "myapp.ini":
- [uwsgi]
- http=:9090
- wsgi-file=server.py
- master=true
- processes=4
- threads=2
- stats=127.0.0.1:9191
然后就可以将启动命令简化为:
$ uwsgi myapp.INI
配置 Nginx
Nginx 的安装可以参考这篇文章 http://www.bjhee.com/lnmp.html , 文本采用的环境就是 Ubuntu Linux, 对于其他系统如 Mac, 基本上差不太多
首先, 我们将 uWSGI 的 HTTP 端口监听改为 socket 端口监听, 即将配置文件中的 "http" 项去掉, 改为 "socket" 项:
- [uwsgi]
- socket=127.0.0.1:3031
- wsgi-file=server.py
- master=true
- processes=4
- threads=2
- stats=127.0.0.1:9191
然后, 打开 Nginx 的配置文件, Ubuntu 上默认是 "/etc/nginx/sites-enabled/default" 文件, 将其中的根路径部分配置为:
- location / {
- include uwsgi_params;
- uwsgi_pass 127.0.0.1:3031;
- }
这段配置表明 Nginx 会将收到的所有请求都转发到 "127.0.0.1:3031″端口上, 即 uWSGI 服务器上. 现在让我们重启 Nginx, 并启动 uWSGI 服务器:
- $ sudo service nginx restart
- $ uwsgi myapp.INI
访问 "http://localhost", 我们会再次看到 "Hello World!".
运行 Flask 应用
其实很简单, 只要将上例中 server.py 的内容改为 Flask 应用即可, 当然你需要先把 Flask 包安装好:
- from flask import Flask
- application = Flask(__name__)
- @application.route('/')
- def index():
- return '<h1>Hello World</h1>'
很多人习惯将 Flask 应用对象取名为 "app", 但是 WSGI 标准是 "application".uWSGI 提供了一个功能, 可以指定应用对象, 方法就是在配置文件中加上 "callable" 项:
- [uwsgi]
- ...
- callable=App
现在, 我们的 Flask 应用就可以使用 "app" 作为对象名了
- from flask import Flask
- App = Flask(__name__)
- @App.route('/')
- def index():
- return '<h1>Hello World</h1>'
使用 Python 虚拟环境
我们永远都是建议采用虚拟环境来避免应用间冲突, uWSGI 可以非常容易做到这点, 就是在配置文件中加上 "virtualenv" 项:
- [uwsgi]
- ...
- virtualenv=/home/bjhee/virtualenv
部署多个应用
一个 Nginx 中, 可以同时运行多个应用, 不一定是 Python 的应用. 我们期望通过不同的路径来路由不同的应用, 因此就不能像上例那样直接修改根目录的配置. 假设我们希望通过 "http://localhost/myapp" 来访问我们的应用, 首先要在 Nginx 的配置文件中, 加入下面的内容:
- location /myapp {
- include uwsgi_params;
- uwsgi_param SCRIPT_NAME /myapp;
- uwsgi_pass 127.0.0.1:3031;
- }
这里我们定义了一个 uWSGI 参数 "SCRIPT_NAME", 值为应用的路径 "/myapp". 接下来, 在 uWSGI 的启动配置中, 去掉 "wsgi-file" 项, 并加上:
- [uwsgi]
- ...
- mount=/myapp=server.py
- manage-script-name=true
"mount" 参数表示将 "/myapp" 地址路由到 "server.py" 中,"manage-script-name" 参数表示启用之前在 Nginx 里配置的 "SCRIPT_NAME" 参数. 再次重启 Nginx 和 uWSGI, 你就可以通过 "http://localhost/myapp" 来访问应用了.
补充内容
上面的所有例子中, 我们是通过 "127.0.0.1:3031″Socket 端口来连接 Nginx 和 uWSGI 的, 其实我们也可以采用 socket 文件的方式, 这样可以不用写死端口. 在 uWSGI 的启动配置中, 我们要修改"socket" 项:
- [uwsgi]
- socket=/tmp/uwsgi.sock
- ...
启动 uWSGI 服务器后, 它会自动创建一个 "/tmp/uwsgi.sock" 文件. 然后让我们修改 Nginx 配置文件, 将 "uwsgi_pass" 配置项改为文件:
- location /myapp {
- include uwsgi_params;
- uwsgi_param SCRIPT_NAME /myapp;
- uwsgi_pass unix:/tmp/uwsgi.sock;
- }
重启 Nginx 服务器即可. 这里我开始一直没跑通, 研究了好久才发现, Nginx 的用户 (默认的 www-date:adm), 必须要对该文件有读写的权限才行. 因为运行 uWSGI 的用户与运行 Nginx 的用户不一样, 而 "/tmp/uwsgi.sock" 是由 uWSGI 的用户创建的, 导致 Nginx 没有足够的权限. 如果朋友们也遇到同样的问题, 那就只能 chmod 了.
另外, 还是要提一下 ".egg" 包的解压缩临时目录, 我们在介绍 mod_wsg http://www.bjhee.com/apache-wsgi.html 的最后提到过, 在 uWSGI 应用中也一样, Linux 上默认是在用户主目录下, 比如 "/home/bjhee/.python-eggs". 你可以通过设置系统环境变量 "PYTHON_EGG_CACHE" 来改变它.
来源: http://www.bubuko.com/infodetail-2881339.html