详解python使用Nginx和uWSGI来运行Python应用


Posted in Python onJanuary 09, 2018

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的安装可以参考这篇文章,文本采用的环境就是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_wsgi的最后提到过,在uWSGI应用中也一样,Linux上默认是在用户主目录下,比如”/home/bjhee/.python-eggs”。你可以通过设置系统环境变量”PYTHON_EGG_CACHE”来改变它。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
用Python脚本生成Android SALT扰码的方法
Sep 18 Python
python批量制作雷达图的实现方法
Jul 26 Python
Python pass详细介绍及实例代码
Nov 24 Python
Python安装官方whl包和tar.gz包的方法(推荐)
Jun 04 Python
python如何读写csv数据
Mar 21 Python
python2和python3实现在图片上加汉字的方法
Aug 22 Python
pygame库实现俄罗斯方块小游戏
Oct 29 Python
Python 3.8 新功能大揭秘【新手必学】
Feb 05 Python
Django choices下拉列表绑定实例
Mar 13 Python
Python类绑定方法及非绑定方法实例解析
Oct 09 Python
python+flask编写一个简单的登录接口
Nov 13 Python
FP-growth算法发现频繁项集——发现频繁项集
Jun 24 Python
Python numpy实现数组合并实例(vstack,hstack)
Jan 09 #Python
运动检测ViBe算法python实现代码
Jan 09 #Python
python+opencv实现动态物体识别
Jan 09 #Python
Python设计模式之门面模式简单示例
Jan 09 #Python
Python和Java进行DES加密和解密的实例
Jan 09 #Python
Python设计模式之中介模式简单示例
Jan 09 #Python
python+opencv实现动态物体追踪
Jan 09 #Python
You might like
桌面中心(一)创建数据库
2006/10/09 PHP
php+mysql结合Ajax实现点赞功能完整实例
2015/01/30 PHP
PHP用mysql_insert_id()函数获得刚插入数据或当前发布文章的ID
2016/11/25 PHP
js重写alert控件(适合学习js的新手朋友)
2014/08/24 Javascript
JavaScript判断文件上传类型的方法
2014/09/02 Javascript
最精简的JavaScript实现鼠标拖动效果的方法
2015/05/11 Javascript
JavaScript实现的多个图片广告交替显示效果代码
2015/09/04 Javascript
JavaScript实现仿新浪微博大厅和腾讯微博首页滚动特效源码
2015/09/15 Javascript
JavaScript判断表单为空及获取焦点的方法
2016/02/12 Javascript
Javascript设计模式之观察者模式(推荐)
2016/03/29 Javascript
全面介绍javascript实用技巧及单竖杠
2016/07/18 Javascript
SVG动画vivus.js库使用小结(实例代码)
2017/09/14 Javascript
javascript基于牛顿迭代法实现求浮点数的平方根【递归原理】
2017/09/28 Javascript
JavaScript实现多重继承的方法分析
2018/01/09 Javascript
微信小程序js文件改变参数并在视图上及时更新【推荐】
2018/06/11 Javascript
基于layui的下拉列表的数据回显方法
2019/09/24 Javascript
laydate只显示时分 不显示秒的功能实现方法
2019/09/28 Javascript
小程序使用wxs解决wxml保留2位小数问题
2019/12/13 Javascript
ant design实现圈选功能
2019/12/17 Javascript
JS实现百度搜索框关键字推荐
2020/02/17 Javascript
[47:50]Secret vs VP 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
Python自动登录126邮箱的方法
2015/07/10 Python
Python实现对字典分别按键(key)和值(value)进行排序的方法分析
2018/12/19 Python
python实现串口通信的示例代码
2020/02/10 Python
Pytorch中的自动求梯度机制和Variable类实例
2020/02/29 Python
领先的钻石和订婚戒指零售商:Diamonds-USA
2016/12/11 全球购物
海外淘书首选:AbeBooks
2017/07/31 全球购物
函数指针的定义是什么
2016/08/14 面试题
外贸英语毕业生自荐信
2013/11/14 职场文书
市场营销专业大学生职业生涯规划文
2014/03/06 职场文书
2015年工商所工作总结
2015/05/21 职场文书
2015年幼儿园学期工作总结
2015/05/22 职场文书
2015年度酒店客房部工作总结
2015/05/25 职场文书
小学运动会前导词
2015/07/20 职场文书
创业计划书之珠宝饰品
2019/08/26 职场文书
如何用JS实现简单的数据监听
2021/05/06 Javascript