介绍
在 Python的Web服务器比较 文章中,我们已经说过,uWSGI是一个庞大的项目,比单纯的 Web应用 功能要复杂得多。然而,正是因为其强大的各种功能,可以容易地将通过配置就满足我们的各种需求,尤其是和 nginx 结合的时候。
在这篇文章中,我们要讨论的 uWSGI 深度不仅仅局限于以前常说的安装服务器,这次我们将会实际部署一个简单的 WSGI Python应用。同时我们也会聊一下 Nginx,因为 Nginx 和 uWSGI 的合作是那么自然,可以说是配合完美的部署栈。
了解 uWSGI 和 Nginx 的使用
uWSGI是一个有着壮志雄心的项目。它提供的工具集不仅仅是简单地作为Web应用程序这么多。由于它在性能等方面表现得非常优异,因此,多年来,它已经成为许多系统管理员和开发人员部署应用的首选工具。
Nginx的,因为从 0.8.40 版本依赖开始支持 uwsgi 协议。这成为使用 uWSGI 运行的 WSGI 应用与 Nginx 通信的最好方式。这也就意味着对你来说,你可以很简单得通过高度灵活的配置就能够获得一个优化的部署。总之,这使得 uWSGI 加 Nginx 成为许多部署方案的最佳选择。
uWSGI 简介
以下是从 DigitalOcean Python服务器比较的文章中提取的内容。
“尽管它的命名规则很混乱,但是 uWSGI 本身就是一个包含很多组件浩大的工程,旨在为软件服务提供一个完整的软件栈。作为组成部分的 uWSGI服务器, 可以运行 Python WSGI应用程序。它支持多种协议,包括自己的 uwsgi 协议(类似于SCGI)。为了满足在应用服务器的前面使用独立的HTTP服务器的需求,NGINX 和 Cherokee Web服务器都提供了模块支持 uWSGI 的 uwsgi协议”。
uWSGI亮点
- uWSGI 本身就是一个WSGI适配器,它完全支持以 WSGI 运行的Python应用程序
- 与libpython链接,在启动时加载应用程序代码,就像一个 Python解释器,解析请求数据,并调用Python可执行对象。
- NGINX Web服务器的直接支持
- 使用 C 语言编写
- 不仅仅只有运行应用程序的组件,扩展方便
- 目前(截至2013年年底),具有快速的发布周期。
- 拥有不同的应用程序执行引擎
- 更低的运行内存占用
使用 Nginx 部署 Web应用程序
Nginx的是一个非常高性能的 Web服务器/反向代理。因为它的轻量级以及轻松扩展。由于出色的架构,能够处理大量的请求(几乎不受限制),只取决于你的应用程序或网站负载,可能在以前的应用中难以找到对手。
请注意: “处理”连接意味着不会丢弃他们,并能与为他们提供服务。你仍然需要保证你的应用程序和数据库运作良好,才能使 Nginx为客户服务的响应不是错误消息。
Nginx 反向代理 uWSGI
很多框架和应用程序服务器可以从实际应用中的反应提供静态文件(如,JavaScript,CSS,图像等)一起使用。然而,更好的事情是让(反向代理)服务器,如Nginx的处理提供这些文件,并管理连接(任务要求)。这减轻了很多的负荷的从应用服务器的,授予你一个更好的整体性能。
随着应用程序的增长,你会想优化它,并在时机成熟时,分发跨服务器(VPS),以便能够同时处理更多的连接,并具有一般比较健壮的体系结构。在应用程序服务器(S)的前面有一个反向代理可以帮助你这个从一开始。
Nginx的的可扩展性(与故障转移和其它机制一起如本地缓存)也是一个伟大的壮举,造福不像(简单)的应用程序服务器的Web应用程序。
一个基本的服务器架构的例子:
Client Request ----> Nginx (Reverse-Proxy)
|
/|\
| | `-> App. Server I. 127.0.0.1:8081
| `--> App. Server II. 127.0.0.1:8082
`----> App. Server III. 127.0.0.1:8083
注意:当一个应用程序设置为侦听传入连接127.0.0.1,这将只可能在本地访问它。如果使用0.0.0.0,那么它将可以接受来自外部的连接。
准备 droplet
在本节中,我们将准备我们使用的虚拟服务器(即部署我们的应用程序的 droplet)。
我们将首先:
- 更新默认的操作系统
- 下载并安装常用的Python的工具(pip,virtualenv)
- 创建虚拟环境中包含应用程序(在其内部的相关性,如 uWSGI Daemon)
注意:这里给出的说明保持简短。要了解更多信息,请访问我们关于的 pip 的 how-to 以及 virtualenv 的文章:常用的 Python 工具:使用 virtualenv 安装 pip 和管理软件包。
更新默认的操作系统
注意:我们将在一个新的VPS进行以下设置和准备使用的操作系统的最新版本。从理论上说,你不应该有你的服务器上尝试他们的问题。但是,如果您已经在积极使用它,我们强烈建议切换到新系统,你尝试了。
为了确保我们拥有的默认应用程序的最新可用版本,我们需要更新我们的系统。
对于基于Debian的系统(如Ubuntu的,Debian的),运行以下命令:
aptitude update
aptitude -y upgrade
设置的Python,PIP和的virtualenv
apt install python-dev
curl https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py | python -
curl https://raw.github.com/pypa/pip/master/contrib/get-pip.py | python -
export PATH="/usr/local/bin:$PATH"
sudo pip install virtualenv
创建一个独立的虚拟(Python)的环境
拥有所有必要的工具,在我们的处置准备好了,我们可以创建一个环境中部署我们的应用程序。
记住:如果你没有得到你的的virtualenv(本地)机为你的项目,你应该考虑创建一个,内移动应用程序(及其依赖)。
让我们创造这将同时包含一个文件夹开始虚拟环境和应用程序模块:
在这里,你可以使用任何名字,以满足您的需求:
mkdir my_app
我们可以继续进入这个文件夹里面,并创建一个新的虚拟环境:
您也可以选择你喜欢的虚拟环境中的任何名称。
cd my_app
virtualenv my_app_venv
让我们创建一个新的文件夹有包含你的Python应用程序模块,以及:
这是你的应用程序模块的文件夹。
mkdir app
并激活虚拟环境中解释使用它:
请确保使用您选择为您的虚拟环境中,如果你去比“我的其他事物的名称应用 venv”。
source my_app_venv/bin/activate
最后,这是你的主要应用程序的部署目录应该怎么样子:
my_app # Main Folder to Contain Everything Together
|
|=== my_app_venv # V. Env. folder with the Python Int.
|=== app # Your application module
|..
|.
如果你觉得每次都要使用
virtualenv my_app_venv
进行环境切换的话,我之前写过一篇文章 virtualenv wrapper 可以帮助你更方便得管理虚拟环境。
下载并安装uWSGI
我的推荐就是在一个项目中,尽可能将所有的依赖都包括在虚拟环境中,所以对于 uWSGI 来说也不例外,所以我也将在这个虚拟环境中下载并安装 uWSGI。
安装 uWSGI 还是老套路,还是要使用 pip,运行以下命令
pip install uwsgi
Tips:要了解更多关于 pip 的内容,例如它的用法和功能,可以参考这篇文章:常用的Python工具:使用 virtualenv 安装 pip 和管理软件包。
下载并安装Nginx
因为 Nginx 不是 Python 的库了,所以也就不能安装在虚拟环境中了,因此我们就得用系统包管理工具来安装 Nginx 了,运行以下命令来使用默认的系统包管理套件安装Nginx:
sudo aptitude install nginx
要运行Nginx的,可以使用以下命令:
sudo service nginx start
要停止Nginx的,可以使用以下命令:
sudo service nginx stop
要重新启动Nginx的,可以使用以下命令:
sudo service nginx restart
或者:
nginx -s reload # 仅仅重新加载配置文件并且重启
注意:要了解更多关于 Ubuntu 上的 Nginx 的信息,可以参阅文章:如何在Ubuntu 12.04安装Nginx。
使用 uWSGI 运行 Python WSGI应用
在本节中,我们将示例一个Python WSGI应用程序是如何在 uWSGI Web容器中运行的。在 uWSGI 中运行 Python 的 WSGI应用与在其他应用容易并没有太大区别。和其他服务器一样,uWSGI 需要你的应用程序为它提供一个入口点(可调用对象/函数)。启动时,这个入口点,包括配置变量,传递给 uWSGI 并开始运行。当一个请求到达时,这个可调用对象需要处理它,并把它传递给你的应用程序来处理。
结构:
........
/|\
| | `-> App. Server I. 127.0.0.1:8080 <--> Application
| `--> App. Server II. 127.0.0.1:8081 <--> Application
.....
WSGI
WSGI简而言之就是一个Web服务器和应用程序本身之间的接口。关于 WSGI 的介绍我以前写过一篇文章:wsgi 简单介绍,有需要可以参考一番。
为了后面的需要,这边需要创建一个简单的WSGI应用对象:wsgi.py。前面说过了,使用 WSGI运行的Web服务器需要一个应用对象(即您的应用程序)。与大多数框架的应用一样,这是由一个的wsgi.py 提供的可调用的应用程序对象。
那现在就让我们创建一个wsgi.py文件,并包含一个基本的WSGI应用程序开始。
运行以下命令使用文本编辑器 nano 创建 wsgi.py:
nano wsgi.py
然后在文本编辑器中敲入我们的 WSGI 应用程序代码:
def application(env, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return ["Hello!"]
当编辑完毕之后,我们就需要按下快捷键:Ctrl + X
然后键入 ‘Y’ 确定保存文件。需要注意的是这个文件的位置是在 my_app 目录下,在全局中与你的虚拟环境目录平级,你的应用程序的部署目录应该是这个样子:
my_app # Main Folder to Contain Everything Together
|
|=== my_app_venv # V. Env. folder with the Python Int.
|=== app # Your application module
|
|--- wsgi.py # File containing application callable
|..
|.
运行服务器
uWSGI 有很多配置和选项参数,也正是因为这些参数和配置才使得它灵活而强大,但是,作为初次使用,我们不需要关注太多,首先来个简单的用法示例:
uwsgi [option] [option 2] .. -w [wsgi file with app. callable]
那么对应到运行我们的 wsgi.py 应用,那么就应该是:
uwsgi --socket 127.0.0.1:8080 --protocol=http -w wsgi
这将在前台运行服务器,如果你想停止它,请按
Ctrl + C
。
重要事项[!]:如果你是按照我们的 Nginx配置 一节中的 Nginx 来运行服务器的话,请务必移除 —protocol=http 这个启动参数,否则 Nginx 和 uWSGI 将不能彼此交谈。
管理uWSGI服务器和处理信号
管理 uWSGI 包括运行时所采取的操作, uWSGI 有操纵进程的各种不同的命令集:
- SIGHUP -HUP 优雅地重新加载 worker 和应用
- SIGTERM -TERM 强制重加载
SIGINT -INT
和SIGQUIT -QUIT
立即杀死所有 worker- SIGUSR1 -USR1 打印统计数据(标准输出)
- SIGUSR2 -USR2 打印 worker 状态
- SIGURG -URG 恢复快照
- SIGTSTP -TSTP 暂停,挂起或恢复实例
- SIGWINCH -WINCH 唤醒被系统调用阻塞的 worker
信号管理的例子:
使用 SIGHUP 重启服务器
这条命令会优雅得重新启动服务器。也就是说,它会等待当前 worker 的当前任务完成,然后再次终止他们,接着继承设置重新启动。
用法: kill -HUP [PID]
如果你不想指定PID,则可以使用 pidfile 选项启动uWSGI,uWSGI 会写入一个文件,然后您可以用它来管理的进程。
Nginx的配置
建立uWSGI来运行我们的应用程序后,我们现在需要做的Nginx同样为它与uWSGI服务器(S)交谈。对于这一点,我们需要修改Nginx的配置文件:nginx.conf
运行以下命令来打开 nginx.conf 并使用 nano 文本编辑器编辑:
sudo nano /etc/nginx/nginx.conf
然后,你可以用下面的示例配置替换文件里面的内容,让 nginx 成为一个反向代理,与你的应用程序进行通信。
Tips:如果想了解如何提供 SSL支持,可以看看这篇文章:在 Nginx 上支持 SSL验证。
nginx 的示例配置:
# nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
sendfile on;
gzip on;
gzip_http_version 1.0;
gzip_proxied any;
gzip_min_length 500;
gzip_disable "MSIE [1-6]\.";
gzip_types text/plain text/xml text/css
text/comma-separated-values
text/javascript
application/x-javascript
application/atom+xml;
# Configuration containing list of application servers
upstream uwsgicluster {
server 127.0.0.1:8080;
# server 127.0.0.1:8081;
# ..
# .
}
# Configuration for Nginx
server {
# Running port
listen 80;
# Settings to by-pass for static files
location ^~ /static/ {
# Example:
# root /full/path/to/application/static/file/dir;
root /app/static/;
}
# Serve a static file (ex. favico) outside static dir.
location = /favico.ico {
root /app/favico.ico;
}
# Proxying connections to application servers
location / {
include uwsgi_params;
uwsgi_pass uwsgicluster;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}
}
当您完成修改配置,按 CTRL + X
,并按 Y
确认保存并退出。您将需要重新启动 Nginx 是使更改生效。
运行重启Nginx的命令如下:
sudo service nginx stop
sudo service nginx start
或者直接这样也行:
sudo nginx -s reload
注意:要了解更多有关Nginx的内容,可以参阅文章:如何在VPS上配置Nginx Web服务器。
配置uWSGI
当启动uWSGI服务于应用时,有几种方式可以应用于例如 socket 运行的必要的配置,例如进程数,主进程设置等。在本节中,我们将讨论其中三种:
- 传递的配置作为参数
- 使用.ini文件进行配置
- 使用.json文件进行配置
注: uWSGI支持各种协议和方式来设置配置文件,如标准输入和HTTP。
选项1:传递结构作为参数:
虽然很容易变得混乱,并且难以重用多次,但是这确实是运行uWSGI最基本的方法,就像任何其他的shell脚本,通过参数提供其必要的配置。
用法示例:
# uwsgi [option] [option 2] .. -w [wsgi.py with application callable]
# Simple server running *wsgi*
uwsgi --socket 127.0.0.1:8080 -w wsgi
# Running Pyramid (Paster) applications
uwsgi --ini-paste production.ini
# Running web2py applications
uwsgi --pythonpath /path/to/app --module wsgihandler
# Running WSGI application with specific module / callable names
uwsgi --module wsgi_module_name --callable application_callable_name
uwsgi -w wsgi_module_name:application_callable_name
选项2:使用.ini文件进行配置
提供 uWSGI配置的另一个(可能)更好的方式是通过 .ini文件。这些文件有一个简单的结构(见下例),并且需要每次执行uWSGI启动脚本的时候明确得指定位置。
.ini结构示例(example_config.ini):
[uwsgi]
# -------------
# Settings:
# key = value
# Comments >> #
# -------------
# socket = [addr:port]
socket = 127.0.0.1:8080
# Base application directory
# chdir = /full/path
chdir = /my_app
# WSGI module and callable
# module = [wsgi_module_name]:[application_callable_name]
module = app:application
# master = [master process (true of false)]
master = true
# processes = [number of processes]
processes = 5
用法示例:
uwsgi --ini example_config.ini
选项#3:使用.json文件结构
使用 .json文件 运行,除了结构之外,大体上与上述的例子相同。
.json结构示例(example_config.json):
{
"uwsgi": {
"socket": ["127.0.0.1:8080"],
"module": "my_app:app",
"master": true,
"processes": 5,
}
}
用法示例:
uwsgi --json example_config.json
Tips: 要了解更多关于配置uWSGI,可以阅读其配置文档。
添加并发和监控
uwsgi --http :9090 --wsgi-file foobar.py --master --processes 4 --threads 2
uwsgi --http :9090 --wsgi-file foobar.py --master --processes 4 --threads 2 --stats 127.0.0.1:9191
更多…
防火墙
保护 SSH
创建告警
监控和观察服务器访问日志日报: