1. 什么是uWSGI?
uWSGI(官方写法为”uWSGI”)是一个Web服务器和应用服务器,用于将Web应用程序和Web服务器之间进行通信。它充当Web服务器和Python Web应用程序之间的桥梁,实现了WSGI协议(Web Server Gateway Interface)的处理。
2. uwsgi、uWSGI和WSGI辨析
WSGI(Web Server Gateway Interface):
WSGI是Python Web应用程序与Web服务器之间的接口规范。它定义了Web应用程序如何与Web服务器进行通信,以便能够处理HTTP请求并生成HTTP响应。WSGI规范旨在提供一种标准的方式来连接Web应用程序和Web服务器,使不同的Web框架和Web服务器能够无缝协作。
uWSGI(官方写法为”uWSGI”):
uWSGI是一个用于实现WSGI协议的Web服务器和应用服务器。它是一个独立的软件项目,提供了一个功能强大且灵活的服务器,用于将Web服务器(如Nginx或Apache)与Python Web应用程序(如Django或Flask)连接起来。uWSGI可以处理大量并发连接,并提供了各种高级功能,如负载均衡、缓存、自动扩展等。
uwsgi(小写的”uwsgi”):
uwsgi是uWSGI服务器的一种通信协议,用于定义uWSGI服务器与Web服务器之间的数据传输格式。uwsgi协议是uWSGI服务器与Web服务器之间进行通信的一种标准化协议。uWSGI服务器可以通过uwsgi协议与Web服务器进行通信,从而实现Web应用程序的处理。
总结来说,WSGI是Python Web应用程序与Web服务器之间的接口规范,uWSGI是一个实现了WSGI协议的Web服务器和应用服务器,而uwsgi是uWSGI服务器与Web服务器之间的通信协议。它们共同构成了将Python Web应用程序与Web服务器进行连接和通信的基础架构。
3. 为什么需要uWSGI?
在生产环境中部署Python Web项目时,uWSGI负责处理Nginx转发的动态请求,并与我们的Python应用程序沟通,同时将应用程序返回的响应数据传递给Nginx。
客户端 <-> Nginx <-> uWSGI <-> Python应用程序(Django, Flask)
Nginx本身就是Web服务器,我们为什么还需要uWSGI这个Web服务器呢?Django不是自带runserver服务器?Flask不是自带Werkzeug吗?答案是Nginx处理静态文件非常优秀,却不能直接与我们的Python Web应用程序进行交互。Django和Flask本身是Web框架,并不是Web服务器,它们自带的runserver和Werkzeug也仅仅用于开发测试环境,生产环境中处理并发的能力太弱。
为了解决Web 服务器与应用程序之间的交互问题,就出现了Web 服务器与应用程序之间交互的规范。最早出现的是CGI,后来又出现了改进 CGI 性能的FasgCGI,Java 专用的 Servlet 规范。在Python领域,最知名的就是WSGI规范了。
WSGI 全称是 Web Server Gateway Interface,也就是 Web 服务器网关接口,是一个web服务器(如uWSGI服务器)与web应用(如用Django或Flask框架写的程序)通信的一种规范。WSGI包含了很多自有协议,其中一个是uwsgi,它用于定义传输信息的类型。
4. uWSGI 的安装及使用
pip install uwsgi
uWSGI 启动方式
启动方式1(只是练习用):通过命令和参数形式
这里使用一个官方的简单示例,
foobar.py
的文件内容为:def application(env, start_response): start_response('200 OK', [('Content-Type','text/html')]) return [b"Hello World"]
启动命令如下:
# 简单启动: uwsgi --http :9090 --wsgi-file foobar.py # 增加并发:生成4个进程,每个进程有2个线程 uwsgi --http :9090 --wsgi-file foobar.py --master --processes 4 --threads 2
如果有一个django项目,那么启动命令如下:
# 语法:uwsgi --http :8000 --module 项目名.wsgi --http # 指定http协议启动socket服务端,可以通过浏览器直接访问 --module # 项目入口文件;例如是django项目第二级目录下的wsgi.py文件 uwsgi --http :8000 --module CRM_project.wsgi
在生产环境中我们通常不会使用命令行启动Python Web项目,而是通常编辑好uWSGI的配置文件
uwsgi.ini
,然后使用如下命令启动Python Web项目。启动方式2(通过配置文件方式启动,生产环境)
uwsgi的配置文件
uwsgi.ini
a. 创建配置文件
touch uwsgi.ini
b. 配置
uwsgi.ini
文件[uwsgi] ; 虚拟环境绝对路径,Docker部署时不需要 home=/opt/python_venv/test_project ; 项目的绝对路径(例:如果是django项目,填django的第一层目录) chdir = /opt/project/test_project ; 项目名 project=flask_demo ; 启动路由:指定启动的协议,当你和nginx结合进行反向代理,就用unix-socket协议,这种方式无法直接访问,只能通过nginx进行反代 socket=0.0.0.0:8000 ; 项目启动入口文件(默认入口函数是application) wsgi-file=main.py ; 入口文件中的函数(比如flask文件中的app) callable=app ; 启用process manager,管理worker进程,worker进程都是这个master进程的子进程 master=True ; 指定开启的工作进程数量,一般指定为cpu的核数即可(填cpu的4倍数量) processes=1 ; 设置每个工作进程的线程数 threads=2 ; 设置用于uwsgi包解析的内部缓存区大小为64k。默认是4k。 buffer-size = 32768 ; 使进程在后台运行,并将日志打到指定的日志文件或者udp服务器 daemonize = /var/log/test_project/uwsgi.log ; 设置最大日志文件大小 ; log-maxsize = 5000000 ; 指定pid文件的位置,记录主进程的pid号。 pidfile=uwsgi.pid ; 当服务器退出的时候自动删除unix socket文件和pid文件。 vacuum = true ; 格式化日志打印 logformat-strftime=true log-date=%%Y-%%m-%%d %%H:%%M:%%S log-format=[%(ftime)] pid: %(pid) %(addr) => host: %(host)%(uri)(%(method)) in %(secs)s %(status) total-size: %(size) bytes
c. 指定
uwsgi.ini
配置文件启动uwsgi --ini uwsgi.ini # 参数 --ini是指定文件的意思
5. uWSGI 常用命令
# 启动uWSGI服务器
$ uwsgi --ini uwsgi.ini
# 重启uWSGI服务器
$ uwsgi --reload uwsgi.pid
# 查看所有uWSGI进程
$ ps aux | grep uwsgi
# 停止uWSGI服务器
$ uwsgi --stop uwsgi.pid # 启动的时候会生成uwsgi.pid文件
6. uWSGI 常用配置
官方配置参数文档:https://uwsgi-docs-zh.readthedocs.io/zh-cn/latest/Options.html
uWSGI常用配置选项如下所示,可根据需要稍稍修改:
[uwsgi]
; 系统下的用户名
uid=test
; 系统下的用户组
gid=test
; 项目名
project=flask_demo
; 虚拟环境绝对路径,Docker部署时不需要
home=/opt/python_venv/test_project
; 项目的绝对路径(例:如果是django项目,填django的第一层目录)
chdir = /opt/project/test_project
; 启动路由:指定启动的协议,当你和nginx结合进行反向代理,就用unix-socket协议,这种方式无法直接访问,只能通过nginx进行反代
; 选项1, 使用unix socket与nginx通信,仅限于uwsgi和nginx在同一主机上情形
; Nginx配置中uwsgi_pass应指向同一socket文件
;socket=/run/uwsgi/%(project).sock
; 选项2,使用TCP socket与nginx通信
; Nginx配置中uwsgi_pass应指向uWSGI服务器IP和端口
socket=0.0.0.0:8000 ; 或则 socket=:8000
; 选项3,使用http协议与nginx通信
; Nginx配置中proxy_pass应指向uWSGI服务器一IP和端口
; http-socket=0.0.0.0:8000
; 项目启动入口文件(默认入口函数是application)
wsgi-file=main.py
; 入口文件中的函数(比如flask文件中的app)
callable=app
; (可替代上面的配置)入口文件(不要.py,模块形式给出,上面两个可合并如下:)
; module=main:app
; 启用process manager,管理worker进程,worker进程都是这个master进程的子进程
master=True
; 指定开启的工作进程数量,一般指定为cpu的核数即可(填cpu的4倍数量)
processes=1
; 设置每个工作进程的线程数
threads=2
; 设置用于uwsgi包解析的内部缓存区大小为64k。默认是4k。
buffer-size = 65536
; 使进程在后台运行,并将日志打到指定的日志文件或者udp服务器
daemonize = /var/log/test_project/uwsgi.log
; 设置最大日志文件大小
; log-maxsize = 5000000
; 指定pid文件的位置,记录主进程的pid号。
pidfile=uwsgi.pid
; 当服务器退出的时候自动删除unix socket文件和pid文件。
vacuum = true
# 当一个请求花费的时间超过这个时间,那么这个请求都会被丢弃。
harakiri=60
#当一个请求被harakiri杀掉会,会输出一条日志
harakiri-verbose=true
#设置平滑的重启(直到处理完接收到的请求)的长等待时间(秒)
reload-mercy=10
#设置工作进程使用虚拟内存超过多少MB就回收重启
reload-on-as=1024
; 格式化日志打印
logformat-strftime=true
log-date=%%Y-%%m-%%d %%H:%%M:%%S
log-format=[%(ftime)] pid: %(pid) %(addr) => host: %(host)%(uri)(%(method)) in %(secs)s %(status) total-size: %(size) bytes
7. uWSGI和Nginx之间的通信方式
unix socket,http-socket和http。Nginx的配置必需与uwsgi配置保持一致。
# 选项1, 使用unix socket与nginx通信
# 仅限于uwsgi和nginx在同一主机上情形
# Nginx配置中uwsgi_pass应指向同一socket文件地址
socket=/run/uwsgi/%(project).sock
# 选项2,使用TCP socket与nginx通信
# Nginx配置中uwsgi_pass应指向uWSGI服务器IP和端口
socket==0.0.0.0:8000 或则 socket=:8000
# 选项3,使用http协议与nginx通信
# Nginx配置中proxy_pass应指向uWSGI服务器IP和端口
http-socket==0.0.0.0:8000
如果你的nginx与uwsgi在同一台服务器上,优先使用本地机器的unix socket进行通信,这样速度更快。此时nginx的配置文件如下所示:
location / {
include /etc/nginx/uwsgi_params;
uwsgi_pass unix:/run/uwsgi/django_test1.sock;
}
如果nginx与uwsgi不在同一台服务器上,两者使用TCP socket通信,nginx可以使用如下配置:
location / {
include /etc/nginx/uwsgi_params;
uwsgi_pass <uWSGI_SERVER_IP:PORT>;
}
如果nginx与uwsgi不在同一台服务器上,两者使用http协议进行通信,nginx配置应修改如下:
location / {
# 注意:proxy_pass后面http必不可少哦!
proxy_pass http://<uWSGI_SERVER_IP:PORT>;
}