区分wsgi、uWSGI、uwsgi、php-fpm、CGI、FastCGI


在学习 Python web 开发时候,可能会遇到诸如 uwsgi,wsgi 等名词,下面通过梳理总结探究它们之间的关系。

CGI

CGI,(Common Gateway Interface)通用网关接口,是一个协议,是外部应用程序(CGI 程序)与 WEB 服务器之间的接口标准,该协议定义了 Web 服务器调用外部应用程序的时候需要输入的参数和给 Web 服务器的返回结果。通俗来说,规定一个程序该如何与 web 服务器程序之间通信,从而可以让这个程序跑在 web 服务器上

起源

最早的 Web 服务器简单地响应浏览器发来的 HTTP 请求,并将存储在服务器上的 HTML 文件返回给浏览器,也就是静态 html。这个场景下的服务器一般被称为 HTTP 服务器,常见的有 Apache 的 httpd 和 Nginx

事物总是不 断发展,网站也越来越复杂,所以出现动态技术。但是服务器并不能直接运行 php,asp 这样的文件,自己不能做,外包给别人吧,但是要与第三做个约定,我给你什么,然后你给我什么,就是握把请求参数发送给你,然后我接收你的处 理结果给客户端。那这个约定就是 common gateway interface,简称 cgi。这个协议可以用 vb,c,php,python 来实现。cgi 只是接口协议,根本不是什么语言。

image.png

引入 CGI 以便客户端请求能够触发 Web 服务器运行另一个外部程序,客户端所输入的数据也会传给这个外部程序,该程序运行结束后会将生成的 HTML 和其他数据通过 Web 服务器再返回给客户端(即动态请求,比如基于 PHP、Python、Java 实现的应用)。利用 CGI 可以针对用户请求动态返回给客户端各种各样动态变化的信息

工作原理

Web 服务器与 CGI 程序的交互
WEB 服务器将根据 CGI 程序的类型决定数据向 CGI 程序的传送方式,一般是通过标准输入/输出流和环境变量来与 CGI 程序间传递数据。 如下图所示:
image.png

CGI 程序通过标准输入(STDIN)和标准输出(STDOUT)来进行输入输出。此外 CGI 程序还通过环境变量来得到输入,操作系统提供了许多环境变量,它们定义了程序的执行环境,应用程序可以存取它们。Web 服务器和 CGI 接口又另外设置了一些环境变量,用来向 CGI 程序传递一些重要的参数。

常用 CGI 环境变量:

**  变量名** 描述
CONTENT_TYPE 这个环境变量的值指示所传递来的信息的 MIME 类型。目前,环境变量 CONTENT_TYPE 一般都是:application/x-www-form-urlencoded,他表示数据来自于 HTML 表单。
CONTENT_LENGTH 如果服务器与 CGI 程序信息的传递方式是 POST,这个环境变量即使从标准输入 STDIN 中可以读到的有效数据的字节数。这个环境变量在读取所输入的数据时必须使用。
HTTP_COOKIE 客户机内的 COOKIE 内容。
HTTP_USER_AGENT 提供包含了版本数或其他专有数据的客户浏览器信息。
PATH_INFO 这个环境变量的值表示紧接在 CGI 程序名之后的其他路径信息。它常常作为 CGI 程序的参数出现。
QUERY_STRING 如果服务器与 CGI 程序信息的传递方式是 GET,这个环境变量的值即使所传递的信息。这个信息经跟在 CGI 程序名的后面,两者中间用一个问号’?’分隔。
REMOTE_ADDR 这个环境变量的值是发送请求的客户机的 IP 地址,例如上面的 192.168.1.67。这个值总是存在的。而且它是 Web 客户机需要提供给 Web 服务器的唯一标识,可以在 CGI 程序中用它来区分不同的 Web 客户机。
REMOTE_HOST 这个环境变量的值包含发送 CGI 请求的客户机的主机名。如果不支持你想查询,则无需定义此环境变量。
REQUEST_METHOD 提供脚本被调用的方法。对于使用 HTTP/1.0 协议的脚本,仅 GET 和 POST 有意义。
SCRIPT_FILENAME CGI 脚本的完整路径
SCRIPT_NAME CGI 脚本的的名称
SERVER_NAME 这是你的 WEB 服务器的主机名、别名或 IP 地址。
SERVER_SOFTWARE 这个环境变量的值包含了调用 CGI 程序的 HTTP 服务器的名称和版本号。例如,上面的值为 Apache/2.2.14(Unix)

##

每当客户请求 CGI 的时候,WEB 服务器就请求操作系统生成一个新的 CGI 解释器进程(如 php-cgi.exe),CGI 的一个进程则处理完一个请求后退出,下一个请求来时再创建新进程。当然,这样在访问量很少没有并发的情况也行。但当访问量增大,并发存在,这种方式就不适合了,于是就有了 FastCGI

FastCGI

FASTCGI 是 Web 服务器(ex:nginx)和语言解释器(ex:uWsgi)两者底层的通信协议的规范,是对 CGI 的开放的扩展。

CGI 的一个扩展,像是一个常驻(long-live)型的 CGI ,废除了 CGI fork-and-execute (来一个请求 fork 一个新进程处理,处理完再把进程 kill 掉)的工作方式,转而使用一种长生存期的方法,减少了进程消耗,提升了性能。

而 FastCGI 则会先 fork 一个 master 进程,解析配置文件,初始化执行环境,然后再 fork 多个 worker 进程(与 Nginx 有点像),当 HTTP 请求过来时,master 进程将其会传递给一个 worker 进程,然后立即可以接受下一个请求,这样就避免了重复的初始化操作,效率自然也就提高了。而且当 worker 进程不够用时,master 进程还可以根据配置预先启动几个 worker 进程等着;当空闲 worker 进程太多时,也会关掉一些,这样不仅提高了性能,还节约了系统资源

php-fpm

FastCGI 只是一个协议规范,需要每个语言具体去实现,PHP-FPM 就是 PHP 版本的 FastCGI 协议实现,有了它,就是实现 PHP 脚本与 Web 服务器(通常是 Nginx)之间的通信,同时它也是一个 PHP SAPI,从而构建起 PHP 解释器与 Web 服务器之间的桥梁

Php-fpm 全称是 php fastcgi process manager 即 php fastcgi 进程管理器,相比 fastcgi 静态的唤起 cgi,fpm 能根据访问的压力动态的唤起 cgi 进程和销毁以到达动态的调整 cgi 数量,这样可以有效的使用内存。除此之外还有其它的一些优点,比如,fpm 还可以平滑的重载 php 配置;由于 fpm 是使用 Unix-Socket 来和服务器通讯,所以也不用再配置 cgi 端口;fpm 有更好的状态输出和 slowlog 日志,502 的时候能给出更多的错误细节。

PHP-FPM 负责管理一个进程池来处理来自 Web 服务器的 HTTP 动态请求,在 PHP-FPM 中,master 进程负责与 Web 服务器进行通信,接收 HTTP 请求,再将请求转发给 worker 进程进行处理,worker 进程主要负责动态执行 PHP 代码,处理完成后,将处理结果返回给 Web 服务器,再由 Web 服务器将结果发送给客户端。这就是 PHP-FPM 的基本工作原理

WSGI / uwsgi / uWSGI

在 python web 开发中,我们经常使用 uwsgi 配合 nginx 部署一个 web 框架,如 Django 或 flask。同时我们又会说,框架和 web 服务器之间要符合 WSGI 协议

那就来厘清一下这几个概念。

web 服务器和 web 框架
在讲 uWSGI 和 WSGI 之前,先要弄清楚 web 开发的两大块,web 服务器和 web 框架。
web 服务器即用来接受客户端请求,建立连接,转发响应的程序。至于转发的内容是什么,交由 web 框架来处理,即处理这些业务逻辑。如查询数据库、生成实时信息等。Nginx 就是一个 web 服务器,Django 或 flask 就是 web 框架。

那么如何实现 uWSGI 和 WSGI 的配合呢?如何做到任意一个 web 服务器,都能搭配任意一个框架呢?这就产生了 WSGI 协议。只要 web 服务器和 web 框架满足 WSGI 协议,它们就能相互搭配。所以 WSGI 只是一个协议,一个约定。而不是 python 的模块、框架等具体的功能。

而 uWSGI,则是实现了 WSGI 协议的一个 web 服务器。即用来接受客户端请求,转发响应的程序。实际上,一个 uWSGI 的 web 服务器,再加上 Django 这样的 web 框架,就已经可以实现网站的功能了。

WSGI

WSGI,(WEB SERVER GATEWAY INTERFACE),Web 服务器网关接口,是一种 Web 服务器网关接口,它是一个 Web 服务器(如 Nginx,uWSGI 等服务器)与 web 应用(如 Flask 框架写的程序)通信的一种规范。当前运行在 WSGI 协议之上的 Web 框架有 Bottle,Flask,Django

实现了 python web 程序与服务器之间交互的通用性。有了这个东西,web.py 或者 bottle 或者 django 等等的 python web 开发框架,就可以轻松地部署在不同的 web server 上了,不需要做任何特殊配置(也需要一些小小的配置调整)
image.png

##

WSGI 协议其实是定义了一种 server 与 application 解耦的规范,即可以有多个实现 WSGI server 的服务器,也可以有多个实现 WSGI application 的框架,那么就可以选择任意的 server 和 application 组合实现自己的 web 应用。例如 uWSGI 和 Gunicorn 都是实现了 WSGI server 协议的服务器,Django,Flask 是实现了 WSGI application 协议的 web 框架,可以根据项目实际情况搭配使用。

像 Django,Flask 框架都有自己实现的简单的 WSGI server,一般用于服务器调试,生产环境下建议用其他 WSGI server,WSGI 服务器的选择很多,包括 uWSGI 和 gunicorn

uwsgi

同 WSGI 一样是一种通信协议
uwsgi 协议是一个 uWSGI 服务器自有的协议,它用于定义传输信息的类型(type of information),每一个 uwsgi packet 前 4byte 为传输信息类型描述,它与 WSGI 相比是两样东西。

uWSGI (服务器)

它是一个 Web 服务器,它实现了 WSGI 协议、uwsgi、http 等协议。用于接收前端服务器转发的动态请求并处理后发给 web 应用程序。
因为 apache 也好,nginx 也罢,它们自己都没有解析动态语言如 php 的功能,而是分派给其他模块来做,比如 apache 就可以说内置了 php 模块,支持的非常爽,让人感觉好像 apache 就支持 php 一样。uwsgi 实现了 WSGI 协议、uwsgi、http 等协议。 Nginx 中 HttpUwsgiModule 的作用是与 uWSGI 服务器进行交换。

uWSGI 是使用 C 编写的,显示了自有的 uwsgi 协议的 Web 服务器。它自带丰富的组件,其中核心组件包含进程管理、监控、IPC 等功能,实现应用服务器接口的请求插件支持多种语言和平台,比如 WSGI、Rack、Lua WSAPI,网管组件实现了负载均衡、代理和理由功能

uWSGI 也可以当做中间件。

  • 如果是 Nginx+uWSGI+App,那 uWSGI 就是一个中间件
  • 如果是 uWSGI+App,那它就是服务器

Nginx+uWGSI

假设我们使用 python 的 Django 框架写了一个网站,现在要将它挂在网上运行,我们一般需要:

  • Nginx 做为代理服务器:负责静态资源发送(js、css、图片等)、动态请求转发以及结果的回复。
  • uWSGI 做为后端服务器:负责接收 Nginx 转发的请求并处理后发给 Django 应用以及接收 Django 应用返回信息转发给 Nginx。
  • Django 应用收到请求后处理数据并渲染相应的返回页面给 uWSGI 服务器。

image.png
一个 Django 应用,通过 WSGI 协议连接 uWSGI 服务器,uWSGI 服务器实现 WSGI、http 等协议,通过 uwsgi 协议和 Nginx 服务器实现 http 的动态请求和转发以及结果

问题:有 uWGSI 了 Django 为什么还需要 Nginx?
一个普通的个人网站,访问量不大的话,当然可以由 uWSGI 和 Django 构成。但是一旦访问量过大,客户端请求连接就要进行长时间的等待。这个时候就出来了分布式服务器,我们可以多来几台 web 服务器,都能处理请求。但是谁来分配客户端的请求连接和 web 服务器呢?Nginx 就是这样一个管家的存在,由它来分配。这也就是由 Nginx 实现反向代理,即代理服务器。
image.png

Nginx 是一个 HTTP 和反向代理服务器

  • 正向代理

    正向的就是由浏览器主动的想代理服务器发出请求,经代理服务器做出处理后再转给目标服务器
  • 反向代理

    反向的就是不管浏览器同不同意,请求都会经过代理服务器处理再发给目标服务器

使用 Nginx 作为反向代理服务器的好处:

  • 安全

不管什么请求都要经过代理服务器,可以避免外部程序直接攻击 Web 服务器

  • 负载均衡

根据请求情况和服务器负载情况,将请求分配给不同的 Web 服务器,保证服务器性能

  • 提高 Web 服务器的 IO 性能

请求从客户端传到 Web 服务器是需要时间的,传递多长时间就会让这个进程阻塞多长时间,而通过反向代理,就可以由反向代理完整接受该请求,然后再传给 Web 服务器,从而保证服务器性能,而且有的一些简单的事情(比如静态文件)可以直接由反向代理处理,不经过 Web 服务器

总结

  • WSGI 是一种通信协议
  • uwsgi 是一种通信协议,常用于在 uWSGI 服务器与其他网络服务器的数据通信
  • 而 uWSGI 是实现了 uwsgi 和 WSGI 两种协议的 Web 服务器

百度百科上说 uwsgi 是一种线路协议而不是通信协议,个人更倾向于 uwsgi 是类似 WSGI 的通信协议的说法,uwsgi 和 WSGI 都是基于 CGI 扩展出来的。

ASGI

异步网关协议接口,一个介于网络协议服务和 Python 应用之间的标准接口,能够处理多种通用的协议类型,包括 HTTP,HTTP2 和 WebSocket。
然而目前的常用的 WSGI 主要是针对 HTTP 风格的请求响应模型做的设计,并且越来越多的不遵循这种模式的协议逐渐成为 Web 变成的标准之一,例如 WebSocket。

ASGI 尝试保持在一个简单的应用接口的前提下,提供允许数据能够在任意的时候、被任意应用进程发送和接受的抽象。并且同样描述了一个新的,兼容 HTTP 请求响应以及 WebSocket 数据帧的序列格式。允许这些协议能通过网络或本地 socket 进行传输,以及让不同的协议被分配到不同的进程中。

WSGI 和 ASGI 的区别

WSGI 是基于 HTTP 协议模式的,不支持 WebSocket,而 ASGI 的诞生则是为了解决 Python 常用的 WSGI 不支持当前 Web 开发中的一些新的协议标准。同时,ASGI 对于 WSGI 原有的模式的支持和 WebSocket 的扩展,即 ASGI 是 WSGI 的扩展。

参考

https://www.cnblogs.com/wanghetao/p/3934350.html
https://baike.baidu.com/item/fastcgi/10880685
https://www.jianshu.com/p/679dee0a4193
https://baijiahao.baidu.com/s?id=1590941335729952485픴=spider&for=pc
https://blog.csdn.net/qq_35318838/article/details/61198183

#


文章作者: Owen Li
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Owen Li !
  目录