在了解了http协议后,我们知晓,一个web server的本质就是

  1. 浏览器发送一个HTTP请求;

  2. 服务器收到请求,生成一个HTML文档;

  3. 服务器把HTML文档作为HTTP响应的Body发送给浏览器;

  4. 浏览器收到HTTP响应,从HTTP Body取出HTML文档并显示。

而用户的请求的结果分静态页面和动态页面两种

静态页面:是一对写死了的html代码,所有的访问者看到的内容都一样,如你访问京东的主页,所有人看到的都一样

动态页面:动态的概念意味着变,程序中体现'变'的概念就是变量,因而在html代码中需要嵌入变量,变量的值的来源需要用一段代码动态生成,这样不同的用户会提交不同的数据给服务端,服务端分析用户提交过来的数据然后执行这段代码,动态生成值后赋值html中变量,然后返回html给用户,这样对每个用户来说收到的页面都是不一样的。比如你登录京东,登录后返回的页面每个人都不一样。

二 什么是web server

用户上网的本质就是在自己这端启动socket client(浏览器),服务的启动socket server(web server)。

基于http协议的学习我们知道,web server主要是用来响应用户的http请求然后返回html页面给用户。

从用户上网的角度来说,早期的互联网只有俩个角色:浏览器<->web server,此时所有的用户访问的都是静态页面

现在主流的web server有apache,nginx,lighttpd等,须知,它们只能接收用户的请求然后生成静态页面

三 什么是网关协议

3.1 引子

随着互联网的发展,网站为每个用户单独定制个人的东西呈现给用户成为了主流,这时候就产生了动态页面的需求。

因web server比如apache只能处理静态请求,所以对于动态请求,你需要编写专门的程序来处理

02-03 网关协议cgi,fastcgi,wsgi,uwsgi

随着互联网的发展,越来越多的用户数据需要永久保存下来,文件是可以永久保存,但是文件的数据处理性能太低,于是数据库慢慢成为了网站大后端的主流

02-03 网关协议cgi,fastcgi,wsgi,uwsgi

 

apache无法处理动态请求,所以我们需要自己编写一个个的功能来处理这些动态请求(注意:这些动态请求有的需要查询数据库有的则不需要)

我们按照一个需要操作数据的动态请求举例,来分析下问题

02-03 网关协议cgi,fastcgi,wsgi,uwsgi
1 #处理动态请求的伪代码,可以称之为web application,或者简web app
2 
3 一:接收apache提交过来的用户请求,触发函数运行
4 二:连接数据库
5 三:操作数据库(增删改查)
6 四:根据获取的数据进行其他逻辑处理
7 五:返回给apache数据
8 六:关闭数据库
02-03 网关协议cgi,fastcgi,wsgi,uwsgi

问题一:

你在编写web app时,需要深入研究apache工作的协议HTTP,等你研究明白了,过去了一百年。这严重影响了开发效率。

问题二:

这只是你针对apache这款web server定制的代码,换成了另外的web server你的程序无法重用

问题三:

这只是针对一种动态请求的代码实现,对于其他的动态请求呢,你仍然需要写重复的代码去处理。

3.2 网关协议

02-03 网关协议cgi,fastcgi,wsgi,uwsgi

 

如何解决问题一:

我们迫切需要在web server与web app之间定义一种标准,用来明细分工,web server对外提供一种标准,web app开发者只要遵循这个标准,那么后者就无需考虑web server到底是如何实现的了而可以专注web app的开发,这个标准就是网关协议

如何解决问题二:

在web server与web app之间定义了标准,那么只要我的web app是遵循这个标准的,换另外一个也遵循该标准的web server,同样可以运行

如何解决问题三:

这里需要引入一个概念叫:web app开发框架(也称web 框架)

web app开发框架用来为web app开发者提供一套现成的开发工具与开发模式,web app开发者不再需要写重复代码了,只需要使用某种现成的web开发框架,一些重复的功能就不用再去重复造轮子了,这极大的提高了开发效率

比如web app开发框架一般本事都是基于网关协议标准实现的,因为你用web app开发框架去开发web app,自然就是遵循某种网关协议标准的,你甚至连这个协议具体是什么都无需知道。

四 网关协议CGI、FastCGI、WSGI、UWSGI

网关协议CGI

什么是CGI?

CGI即通用网关接口(Common Gateway Interface),是web app应用程序(CGI程序)与Web服务器之间的接口标准。。

CGI 的跨平台性能极佳,几乎可以在任何操作系统上实现。

fork-and-execute模式:apache接收用户动态请求,先要创建cgi的子进程,然后处理请求,处理完后结束这个子进程。

fork-and-execute模式的弊端:用cgi方式的服务器有多少连接请求就会有多少cgi子进程,子进程反复加载是cgi性能低下的主要原因。当用户请求数量非常多时,会大量挤占系统的资源如内存,CPU时间等,造成效能低下。

CGI脚本的工作流程:

  1. 浏览器发送动态请求(通过HTML表单或者超链接)
  2. 服务端接收该请求,调用CGI脚本,产生一个CGI进程来处理该动态请求,结果返回给服务器
  3. 服务器将html返回给浏览器

网关协议FASTCGI

什么是FASTCGI?

FastCGI是从CGI发展改进而来的

传统CGI接口方式的主要缺点是性能很差,因为每次HTTP服务器遇到动态请求时都需要重新启动脚本解析器来处理,然后返回结果给HTTP服务器。无法应对高并非场景。

FastCGI像是一个常驻(long-live)型的CGI,它可以一直执行着,只要激活后,不会每次都要花费时间去fork一次(这是CGI最为人诟病的fork-and-execute 模式)。

CGI 就是所谓的短生存期应用程序,FastCGI 就是所谓的长生存期应用程序。

由于 FastCGI 程序并不需要不断的产生新进程,可以大大降低服务器的压力并且产生较高的应用效率。它的速度效率最少要比CGI 技术提高 5 倍以上。它还支持分布式的运算, 即 FastCGI 程序可以在网站服务器以外的主机上执行并且接受来自其它网站服务器来的请求。

 

FastCGI是语言无关的、可伸缩架构的CGI开放扩展,其主要行为是将CGI解释器进程保持在内存中并因此获得较高的性能。众所周知,CGI解释器的反复加载是CGI性能低下的主要原因,如果CGI解释器保持在内存中并接受FastCGI进程管理器调度,则可以提供良好的性能、伸缩性、Fail-Over特性等等。FastCGI接口方式采用C/S结构,可以将HTTP服务器和脚本解析服务器分开,同时在脚本解析服务器上启动一个或者多个脚本解析守护进程。当HTTP服务器每次遇到动态程序时,可以将其直接交付给FastCGI进程来执行,然后将得到的结果返回给浏览器。这种方式可以让HTTP服务器专一地处理静态请求或者将动态脚本服务器的结果返回给客户端,这在很大程度上提高了整个应用系统的性能。

FastCGI的工作流程:

  1. Web Server启动时载入FastCGI进程管理器(PHP-CGI或者PHP-FPM或者spawn-cgi)
  2. FastCGI进程管理器自身初始化,启动多个CGI解释器进程(可见多个php-cgi)并等待来自Web Server的连接。
  3. 当客户端请求到达Web Server时,FastCGI进程管理器选择并连接到一个CGI解释器。Web server将CGI环境变量和标准输入发送到FastCGI子进程php-cgi。
  4. FastCGI子进程完成处理后将标准输出和错误信息从同一连接返回Web Server。当FastCGI子进程关闭连接时,请求便告处理完成。FastCGI子进程接着等待并处理来自FastCGI进程管理器(运行在Web Server中)的下一个连接。 在CGI模式中,php-cgi在此便退出。

FastCGI 的特点

  1. 打破传统页面处理技术。传统的页面处理技术,程序必须与 Web 服务器或 Application 服务器处于同一台服务器中。这种历史已经早N年被FastCGI技术所打破,FastCGI技术的应用程序可以被安装在服务器群中的任何一台服务器,而通过 TCP/IP 协议与 Web 服务器通讯,这样做既适合开发大型分布式 Web 群,也适合高效数据库控制。
  2. 明确的请求模式。CGI 技术没有一个明确的角色,在 FastCGI 程序中,程序被赋予明确的角色(响应器角色、认证器角色、过滤器角色)。
PHP-CGI是PHP自带的FastCGI管理器。PHP-CGI的不足:

php-cgi变更php.ini配置后需重启php-cgi才能让新的php-ini生效,不可以平滑重启
直接杀死php-cgi进程php就不能运行了。(PHP-FPM和Spawn-FCGI就没有这个问题,守护进程会平滑从新生成新的子进程。)
PHP-CGI
Spawn-FCGI是一个通用的FastCGI管理服务器,它是lighttpd中的一部份,很多人都用Lighttpd的Spawn-FCGI进行FastCGI模式下的管理工作,不过有不少缺点。而PHP-FPM的出现多少缓解了一些问题,但PHP-FPM有个缺点就是要重新编译,这对于一些已经运行的环境可能有不小的风险),在php 5.3.3中可以直接使用PHP-FPM了。Spawn-FCGI的代码很少,全部才630行,用c语言编写,最近一次提交是5年前。代码主页:https://github.com/lighttpd/spawn-fcgi

Spawn-FCGI代码分析如下:

spawn-fcgi 首先create socket,bind,listen 3步创建服务器socket,(把这个socket叫做 fcgi_fd)
用dup2,把fcgi_fd 交换给 FCGI_LISTENSOCK_FILENO (FCGI_LISTENSOCK_FILENO数值上等于0,这是fastcgi协议当中指定用来listen的socket id)
执行execl ,replaces the current process image with a new process image. process image 进程在运行空间的代码段
很显然,Spawn-FCGI也是 pre-fork 模型,只是用了上古C语言编写,充满了N多 unix下暗黑编程技巧。

Spawn-FCGI功能很单一:

只管fork进程,子进程挂了,主进程仅仅log记录一次,根本不会重新fork。在2009年一段时间内,我曾经用spawn-fcgi部署php-cgi,当跑一段时间就会全挂掉,只能用crontab定时重启spawn-fcgi
不负责子进程中的网络IO,把socket放到指定位置就完了,接下来的事情由被spawn的程序处理
Spawn-FCGI是一个很早期的程序,瞻仰一下即可。另外有:1996年的一段代码:http://www.fastcgi.com/om_archive/kit/cgi-fcgi/cgi-fcgi.c,和spawn-fcgi一个风格
Spawn-FCGI

相关文章: