CGI 与 WSGI

1.
首先,CGI是外部应用程序与 Web 服务器之间的接口标准,不同类型语言写的程序只要符合 CGI 标准,就能作为一个 CGI 程序与 Web 服务器交互,早期的 CGI 大多都是c或c++。php可以作为一个 CGI 使用,作为 CGI 时,它将作为独立的进程运行,有请求过来就创建一个进程进行响应。当php作为apache的一个模块时,php将作为apache的一个子进程存在,接受apache调用。现在也有了php-fpm+nginx的组合,php-fpm是一个fast-cgi管理器,负责将接收到的请求分配给预先生成的php子程序,管理着php进程。


2.
CGI不是一种语言,也不是一种技术,而是一种模式。
CGI 的定义 Common Gateway Interface,“通用网关接口”,简称CGI。在物理上是一段程序,运行在服务器上,提供同客户端 HTML页面的接口
换句话,只要是提供HTML的服务器端程序都可以叫CGI,APS、PHP、JSP这些都是,你用C语言写一个可以提供HTML的服务器端EXE文件,也叫CGI。


3.
PHP 网站部署很多都是通过 Nginx + FastCGI 方式
以下叙述仅限于是狭义上的 CGI,即不包含 FastCGI。
对一个 CGI 程序,做的工作其实只有:从环境变量(environment variables)和标准输入(standard input)中读取数据、处理数据、向标准输出(standard output)输出数据。
环境变量中存储的叫 Request Meta-Variables,也就是诸如 QUERY_STRING、PATH_INFO 之类的东西,这些是由 Web Server 通过环境变量传递给 CGI 程序的,CGI 程序也是从环境变量中读取的。
标准输入中存放的往往是用户通过 PUTS 或者 POST 提交的数据,这些数据也是由 Web Server 传过来的。
就比如,我们刚学 C 语言时写的 Hello World,也可以作为一个合法的 CGI 程序。
现在用 CGI 的已经很少了,因为每个 CGI 进程只处理一个请求,换句话说,每个请求都需要创建一个 CGI 进程处理,CGI 程序处理完毕后就退出了。
FastCGI 正是对 CGI 的改进,而且改进了不是一点点。从总体上看,一个 FastCGI 进程可以处理若干请求(一般 FastCGI 进程是驻留着的,但不排除 IIS 之类的 Web Server 限制其空闲时间,在一段时间内没有请求就自动退出的可能),Web Server 或者 fpm 会控制 FastCGI 进程的数量。
细节方面,FastCGI 是一套协议,不再是通过简单的环境变量、标准输入和标准输出来接收和传递数据了。一般来说,FastCGI 用 TCP 或者命名管道(Named Pipe)传输数据。现在绝大多数 PHP 网站都是在用 FastCGI 的。


4.
现在以CGI方式运行的服务器应该已经没有了,PHP是FastCGI,也是这个协议还能续到今天的最主要的原因。Servlet和Python的WSGI可以类比,它是一种编程接口,通过这种编程接口可以将Web Server和Web应用清晰地划分开界限,每个进入的请求将会调用一次Servlet的接口,这样Web应用就无需关心Web Server使用了多线程还是多进程还是多路复用等技术细节,而只需要实现这个接口就行了。既然是编程接口,那么肯定是跟编程语言有关的,Servlet就只能用在Java中,其他语言是不能用Servlet编程的(除非有办法做到和Java兼容)
FastCGI是一种网络协议,它是工作在socket上、而与语言无关的。以前的CGI一般来说是每个请求进来时,从server fork出一个进程,仅仅处理这一个请求,处理完成就退出,处理的过程是从环境变量中获取HTTP头,从标准输入中读取POST数据,从标准输出中输出HTTP响应。由于需要不停地创建和销毁进程,这种实现方式性能是比较低下的,功能也受到许多限制。FastCGI是CGI的一种改进,它在单个连接上接受连续的多个请求,一个一个进行处理,这样就提高了吞吐量。FastCGI和CGI一样与语言无关,任何语言只要遵循FastCGI的协议就可以使用FastCGI;但是它的处理模型是受限的,通常在单个连接上一次只能处理一个请求,这样要达到一定的并发度,就必须创建许多进程(FastCGI也有multiplexing的功能,但不知道支持的如何)
但是其实从Web应用的角度来看,两者的区别并不大,PHP虽然使用FastCGI,但也是对每个请求调用一次PHP脚本。虽然许多PHP程序员喜欢把网页和代码混在一起弄得很难维护,但PHP也是支持使用OOP的方式,像Java一样使用MVC的;Java也同样支持JSP这样的可以嵌入代码的模板。区别有一些,比如Java在同一个进程中工作,可以调用全局对象,可以使用额外的线程池等等,而PHP的对象的生命周期基本限制在单个请求范围内之类,但许多东西还是类似的,都是面向Request进行编程。


5.
一个HTTP请求到达一台服务器的80端口的时候,需要有个程序来响应这个请求。所谓HTTP response,其实只是运行一个程序,它的输入是HTTP request header,它的返回是HTTP response。程序运行方式的区别、HTTP request header的传递方式区别就是CGI、WSGI以及其他各种GI的区别。
如果是CGI,通常来说是一个web server(例如apache、nginx)接收到请求后,将请求中的HTTP request header按照一定规则设置成环境变量,然后启动一个程序(Python脚本),将stdout的输出(其中包含HTTP response header)当成HTTP response返回给客户端。
如果是Django跑在uWSGi、unicorn之类的容器里,那么程序是一个常驻进程,web server和Python进程用WSGI协议传递HTTP request header信息,然后返回给用户。
如果是Django的dev server,它使用Python自带的wsgiref模块实现了一个简单的HTTP server (https://github.com/django/django/blob/master/django/core/servers/basehttp.py),响应HTTP请求。


6.
Tornado: HTTP 服务器、WSGI 框架(很少用)
CGI: 古老的动态 HTTP 服务方式,极其低效、容易出漏洞。Perl 盛行的时代很常用。
WSGI: Python 的 HTTP 接口协议
FastCGI: PHP 等的接口协议。PHP 也是唯一一个把 FastCGI 实现得像 CGI 的 FastCGI 实现(HTTP 头可通过环境变量访问)
uwsgi: 它是一个软件。是 WSGI、PSGI 等等的容器。也就是它实现了这些协议。同样实现了 WSGI 的还有 gunicorn 之类的。
nginx: 可以作为代理,把 HTTP 传给 Tornado。也可以作为网关,把 HTTP 转成 FastCGI、uwsgi 协议传给后边的程序。


server 和 application 直接按 WSGI 的约定调用,它们在一个进程内。
uwsgi 是 nginx 和 uwsgi 之间的通信协议。


5.
Tornado可以当作HTTP server,直接TCP开始实现HTTP服务,这也就是为啥说Tornado可以不经过WSGI。实际上它也不是CGI,CGI是指通过stdin和stdout进行HTTP的请求处理,WSGI则是包裹成一个Python对象来传递请求和响应。
WSGI是写入PEP的python的HTTP接口,然而缺点是这个借口是完全同步的,Tornado最大的特点是可以异步处理请求,然而如果使用WSGI,那就不能做到了。官方文档明确指出,将Tornado应用作为WSGI应用时异步接口全部不可用。
相反,Tornado可以作为HTTP server向其它框架提供WSGI容器,所以可以用Tornado来做apache/nginx/guicorn之类的事情。
所以对Tornado而言,如果还要使用nginx之类做前置,正确的姿势应当是通过反向代理来做负载均衡。


6.
作者:灵剑
链接:https://www.zhihu.com/question/46945479/answer/104066078


WSGI是一种编程接口,而uwsgi是一种传输协议,从作用上来讲,的确跟fastcgi是最接近的。跟fastcgi的区别在于它是面向多并发的。我们知道fastcgi是CGI的替代品,它的工作方式仍然跟CGI是类似的,当一个请求进入的时候,通过socket发送请求的环境变量,然后发送POST数据(相当于CGI的stdin),然后等待程序输出(相当于CGI的stdout),等输出结束后,再发送下一个请求。这就导致fastcgi最大的并发量被限制为fastcgi后端的数量,显然这样的服务器模式对于并发量很大、单个请求耗时比较长的服务是不合适的,因此很多时候我们不愿意使用fastcgi部属而是使用反向代理的方式配置。
但是跟反向代理比起来,fastcgi显然也是有好处的,最重要的好处在于解析HTTP协议的部分被offload到了前端服务器一级,后端服务器不再解析HTTP协议,这样就减轻了后端的压力,由于前端是nginx这样用C/C++高性能实现的服务器,比起在后端的Python当中使用脚本语言解析HTTP协议,效率要高不少。
uwsgi想要继承fastcgi的这种好处,它通过将消息分片的方式,可以在一个socket上并发传输多个请求,这样就解决了一个连接上一次只能传输一个请求的问题。熟悉HTTP2.0的话会发现这个分片机制跟HTTP2.0很像。

猜你喜欢

转载自blog.csdn.net/ChristopherChen/article/details/78078927
CGI