介绍

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服务器都提供了模块支持 uWSGIuwsgi协议”。

uWSGI亮点

使用 Nginx 部署 Web应用程序

Nginx的是一个非常高性能的 Web服务器/反向代理。因为它的轻量级以及轻松扩展。由于出色的架构,能够处理大量的请求(几乎不受限制),只取决于你的应用程序或网站负载,可能在以前的应用中难以找到对手。

请注意: “处理”连接意味着不会丢弃他们,并能与为他们提供服务。你仍然需要保证你的应用程序和数据库运作良好,才能使 Nginx为客户服务的响应不是错误消息。

Nginx 反向代理 uWSGI

很多框架和应用程序服务器可以从实际应用中的反应提供静态文件(如,JavaScript,CSS,图像等)一起使用。然而,更好的事情是让(反向代理)服务器,如Nginx的处理提供这些文件,并管理连接(任务要求)。这减轻了很多的负荷的从应用服务器的,授予你一个更好的整体性能。

随着应用程序的增长,你会想优化它,并在时机成熟时,分发跨服务器(VPS),以便能够同时处理更多的连接,并具有一般比较健壮的体系结构。在应用程序服务器(S)的前面有一个反向代理可以帮助你这个从一开始。

Nginx的的可扩展性(与故障转移和其它机制一起如本地缓存)也是一个伟大的壮举,造福不像(简单)的应用程序服务器的Web应用程序。

一个基本的服务器架构的例子:

  1. Client Request ----> Nginx (Reverse-Proxy)
  2. |
  3. /|\
  4. | | `-> App. Server I. 127.0.0.1:8081
  5. | `--> App. Server II. 127.0.0.1:8082
  6. `----> App. Server III. 127.0.0.1:8083

注意:当一个应用程序设置为侦听传入连接127.0.0.1,这将只可能在本地访问它。如果使用0.0.0.0,那么它将可以接受来自外部的连接。

准备 droplet

在本节中,我们将准备我们使用的虚拟服务器(即部署我们的应用程序的 droplet)。

我们将首先:

注意:这里给出的说明保持简短。要了解更多信息,请访问我们关于的 pip 的 how-to 以及 virtualenv 的文章:常用的 Python 工具:使用 virtualenv 安装 pip 和管理软件包

更新默认的操作系统

注意:我们将在一个新的VPS进行以下设置和准备使用的操作系统的最新版本。从理论上说,你不应该有你的服务器上尝试他们的问题。但是,如果您已经在积极使用它,我们强烈建议切换到新系统,你尝试了。

为了确保我们拥有的默认应用程序的最新可用版本,我们需要更新我们的系统。

对于基于Debian的系统(如Ubuntu的,Debian的),运行以下命令:

  1. aptitude update
  2. aptitude -y upgrade

设置的Python,PIP和的virtualenv

  1. apt install python-dev
  2. curl https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py | python -
  3. curl https://raw.github.com/pypa/pip/master/contrib/get-pip.py | python -
  4. export PATH="/usr/local/bin:$PATH"
  5. sudo pip install virtualenv

创建一个独立的虚拟(Python)的环境

拥有所有必要的工具,在我们的处置准备好了,我们可以创建一个环境中部署我们的应用程序。

记住:如果你没有得到你的的virtualenv(本地)机为你的项目,你应该考虑创建一个,内移动应用程序(及其依赖)。

让我们创造这将同时包含一个文件夹开始虚拟环境和应用程序模块:

在这里,你可以使用任何名字,以满足您的需求:

mkdir my_app 我们可以继续进入这个文件夹里面,并创建一个新的虚拟环境:

您也可以选择你喜欢的虚拟环境中的任何名称。

  1. cd my_app
  2. virtualenv my_app_venv

让我们创建一个新的文件夹有包含你的Python应用程序模块,以及:

这是你的应用程序模块的文件夹。

mkdir app
并激活虚拟环境中解释使用它:

请确保使用您选择为您的虚拟环境中,如果你去比“我的其他事物的名称应用 venv”。

source my_app_venv/bin/activate
最后,这是你的主要应用程序的部署目录应该怎么样子:

  1. my_app # Main Folder to Contain Everything Together
  2. |
  3. |=== my_app_venv # V. Env. folder with the Python Int.
  4. |=== app # Your application module
  5. |..
  6. |.

如果你觉得每次都要使用 virtualenv my_app_venv 进行环境切换的话,我之前写过一篇文章 virtualenv wrapper 可以帮助你更方便得管理虚拟环境。

下载并安装uWSGI

我的推荐就是在一个项目中,尽可能将所有的依赖都包括在虚拟环境中,所以对于 uWSGI 来说也不例外,所以我也将在这个虚拟环境中下载并安装 uWSGI。

安装 uWSGI 还是老套路,还是要使用 pip,运行以下命令

  1. pip install uwsgi

Tips:要了解更多关于 pip 的内容,例如它的用法和功能,可以参考这篇文章:常用的Python工具:使用 virtualenv 安装 pip 和管理软件包

下载并安装Nginx

因为 Nginx 不是 Python 的库了,所以也就不能安装在虚拟环境中了,因此我们就得用系统包管理工具来安装 Nginx 了,运行以下命令来使用默认的系统包管理套件安装Nginx:

  1. sudo aptitude install nginx

注意:要了解更多关于 Ubuntu 上的 Nginx 的信息,可以参阅文章:如何在Ubuntu 12.04安装Nginx

使用 uWSGI 运行 Python WSGI应用

在本节中,我们将示例一个Python WSGI应用程序是如何在 uWSGI Web容器中运行的。在 uWSGI 中运行 Python 的 WSGI应用与在其他应用容易并没有太大区别。和其他服务器一样,uWSGI 需要你的应用程序为它提供一个入口点(可调用对象/函数)。启动时,这个入口点,包括配置变量,传递给 uWSGI 并开始运行。当一个请求到达时,这个可调用对象需要处理它,并把它传递给你的应用程序来处理。

结构:

  1. ........
  2. /|\
  3. | | `-> App. Server I. 127.0.0.1:8080 <--> Application
  4. | `--> App. Server II. 127.0.0.1:8081 <--> Application
  5. .....

WSGI

WSGI简而言之就是一个Web服务器和应用程序本身之间的接口。关于 WSGI 的介绍我以前写过一篇文章:wsgi 简单介绍,有需要可以参考一番。

为了后面的需要,这边需要创建一个简单的WSGI应用对象:wsgi.py。前面说过了,使用 WSGI运行的Web服务器需要一个应用对象(即您的应用程序)。与大多数框架的应用一样,这是由一个的wsgi.py 提供的可调用的应用程序对象。

那现在就让我们创建一个wsgi.py文件,并包含一个基本的WSGI应用程序开始。

运行以下命令使用文本编辑器 nano 创建 wsgi.py:

  1. nano wsgi.py

然后在文本编辑器中敲入我们的 WSGI 应用程序代码:

  1. def application(env, start_response):
  2. start_response('200 OK', [('Content-Type', 'text/html')])
  3. return ["Hello!"]

当编辑完毕之后,我们就需要按下快捷键:Ctrl + X 然后键入 ‘Y’ 确定保存文件。需要注意的是这个文件的位置是在 my_app 目录下,在全局中与你的虚拟环境目录平级,你的应用程序的部署目录应该是这个样子:

  1. my_app # Main Folder to Contain Everything Together
  2. |
  3. |=== my_app_venv # V. Env. folder with the Python Int.
  4. |=== app # Your application module
  5. |
  6. |--- wsgi.py # File containing application callable
  7. |..
  8. |.

运行服务器

uWSGI 有很多配置和选项参数,也正是因为这些参数和配置才使得它灵活而强大,但是,作为初次使用,我们不需要关注太多,首先来个简单的用法示例:

  1. uwsgi [option] [option 2] .. -w [wsgi file with app. callable]

那么对应到运行我们的 wsgi.py 应用,那么就应该是:

  1. uwsgi --socket 127.0.0.1:8080 --protocol=http -w wsgi

这将在前台运行服务器,如果你想停止它,请按 Ctrl + C

重要事项[!]:如果你是按照我们的 Nginx配置 一节中的 Nginx 来运行服务器的话,请务必移除 —protocol=http 这个启动参数,否则 Nginx 和 uWSGI 将不能彼此交谈。

管理uWSGI服务器和处理信号

管理 uWSGI 包括运行时所采取的操作, uWSGI 有操纵进程的各种不同的命令集:

信号管理的例子:

使用 SIGHUP 重启服务器

这条命令会优雅得重新启动服务器。也就是说,它会等待当前 worker 的当前任务完成,然后再次终止他们,接着继承设置重新启动。

  1. 用法: kill -HUP [PID]

如果你不想指定PID,则可以使用 pidfile 选项启动uWSGI,uWSGI 会写入一个文件,然后您可以用它来管理的进程。

Nginx的配置

建立uWSGI来运行我们的应用程序后,我们现在需要做的Nginx同样为它与uWSGI服务器(S)交谈。对于这一点,我们需要修改Nginx的配置文件:nginx.conf

运行以下命令来打开 nginx.conf 并使用 nano 文本编辑器编辑:

  1. sudo nano /etc/nginx/nginx.conf

然后,你可以用下面的示例配置替换文件里面的内容,让 nginx 成为一个反向代理,与你的应用程序进行通信。

Tips:如果想了解如何提供 SSL支持,可以看看这篇文章:在 Nginx 上支持 SSL验证

nginx 的示例配置:

  1. # nginx.conf
  2. worker_processes 1;
  3. events {
  4. worker_connections 1024;
  5. }
  6. http {
  7. sendfile on;
  8. gzip on;
  9. gzip_http_version 1.0;
  10. gzip_proxied any;
  11. gzip_min_length 500;
  12. gzip_disable "MSIE [1-6]\.";
  13. gzip_types text/plain text/xml text/css
  14. text/comma-separated-values
  15. text/javascript
  16. application/x-javascript
  17. application/atom+xml;
  18. # Configuration containing list of application servers
  19. upstream uwsgicluster {
  20. server 127.0.0.1:8080;
  21. # server 127.0.0.1:8081;
  22. # ..
  23. # .
  24. }
  25. # Configuration for Nginx
  26. server {
  27. # Running port
  28. listen 80;
  29. # Settings to by-pass for static files
  30. location ^~ /static/ {
  31. # Example:
  32. # root /full/path/to/application/static/file/dir;
  33. root /app/static/;
  34. }
  35. # Serve a static file (ex. favico) outside static dir.
  36. location = /favico.ico {
  37. root /app/favico.ico;
  38. }
  39. # Proxying connections to application servers
  40. location / {
  41. include uwsgi_params;
  42. uwsgi_pass uwsgicluster;
  43. proxy_redirect off;
  44. proxy_set_header Host $host;
  45. proxy_set_header X-Real-IP $remote_addr;
  46. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  47. proxy_set_header X-Forwarded-Host $server_name;
  48. }
  49. }
  50. }

当您完成修改配置,按 CTRL + X,并按 Y 确认保存并退出。您将需要重新启动 Nginx 是使更改生效。

运行重启Nginx的命令如下:

  1. sudo service nginx stop
  2. sudo service nginx start

或者直接这样也行:

  1. sudo nginx -s reload

注意:要了解更多有关Nginx的内容,可以参阅文章:如何在VPS上配置Nginx Web服务器

配置uWSGI

当启动uWSGI服务于应用时,有几种方式可以应用于例如 socket 运行的必要的配置,例如进程数,主进程设置等。在本节中,我们将讨论其中三种:

注: uWSGI支持各种协议和方式来设置配置文件,如标准输入和HTTP。

选项1:传递结构作为参数:

虽然很容易变得混乱,并且难以重用多次,但是这确实是运行uWSGI最基本的方法,就像任何其他的shell脚本,通过参数提供其必要的配置。

用法示例:

  1. # uwsgi [option] [option 2] .. -w [wsgi.py with application callable]
  2. # Simple server running *wsgi*
  3. uwsgi --socket 127.0.0.1:8080 -w wsgi
  4. # Running Pyramid (Paster) applications
  5. uwsgi --ini-paste production.ini
  6. # Running web2py applications
  7. uwsgi --pythonpath /path/to/app --module wsgihandler
  8. # Running WSGI application with specific module / callable names
  9. uwsgi --module wsgi_module_name --callable application_callable_name
  10. uwsgi -w wsgi_module_name:application_callable_name

选项2:使用.ini文件进行配置

提供 uWSGI配置的另一个(可能)更好的方式是通过 .ini文件。这些文件有一个简单的结构(见下例),并且需要每次执行uWSGI启动脚本的时候明确得指定位置。

.ini结构示例(example_config.ini):

  1. [uwsgi]
  2. # -------------
  3. # Settings:
  4. # key = value
  5. # Comments >> #
  6. # -------------
  7. # socket = [addr:port]
  8. socket = 127.0.0.1:8080
  9. # Base application directory
  10. # chdir = /full/path
  11. chdir = /my_app
  12. # WSGI module and callable
  13. # module = [wsgi_module_name]:[application_callable_name]
  14. module = app:application
  15. # master = [master process (true of false)]
  16. master = true
  17. # processes = [number of processes]
  18. processes = 5

用法示例:

  1. uwsgi --ini example_config.ini

选项#3:使用.json文件结构

使用 .json文件 运行,除了结构之外,大体上与上述的例子相同。

.json结构示例(example_config.json):

  1. {
  2. "uwsgi": {
  3. "socket": ["127.0.0.1:8080"],
  4. "module": "my_app:app",
  5. "master": true,
  6. "processes": 5,
  7. }
  8. }

用法示例:

  1. uwsgi --json example_config.json

Tips: 要了解更多关于配置uWSGI,可以阅读其配置文档

添加并发和监控

  1. uwsgi --http :9090 --wsgi-file foobar.py --master --processes 4 --threads 2
  2. uwsgi --http :9090 --wsgi-file foobar.py --master --processes 4 --threads 2 --stats 127.0.0.1:9191

更多…

防火墙

保护 SSH

创建告警

监控和观察服务器访问日志日报:

Reference