第一:静态页面和动态页面
上一篇博客介绍了HTTP后,我们知道一个web server的本质就是
-
浏览器发送一个HTTP请求;
-
服务器收到请求,生成一个HTML文档;
-
服务器把HTML文档作为HTTP响应的Body发送给浏览器;
-
浏览器收到HTTP响应,从HTTP Body取出HTML文档并显示。
用户的请求的结果可分为静态页面和动态页面两种
静态页面:是实实在在保存在服务器上写死了的html代码,每个网页都是一个独立的文件,所有的访问者看到的内容都一样
动态页面:动态的概念意味着变,程序中体现'变'的概念就是变量,因而在html代码中需要嵌入变量,变量的值的来源需要用一段代码动态生成,这样不同的用户会提交不同的数据给服务端,服务端分析用户提交过来的数据然后执行这段代码,动态生成值后赋值html中变量,然后返回html给用户,这样对每个用户来说收到的页面都是不一样的。
第二:什么是Web Server
Web Service也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的其它系统中传递过来的请求,轻量级的独立的通讯技术。是:通过SOAP在Web上提供的软件服务,使用WSDL文件进行说明,并通过UDDI进行注册。
通俗来说:用户上网的本质就是在自己这端启动socket client(浏览器),服务的启动socket server(web server)。基于http协议的学习我们知道,web server主要是用来响应用户的http请求然后返回html页面给用户。
现在主流的web server:nginx,apache,tomcat等等
第三:什么是网关协议
引言:
因web server比如apache只能处理静态请求,所以对于动态请求,你需要编写专门的程序来处理
随着互联网的发展,越来越多的用户数据需要永久保存下来,文件是可以永久保存,但是文件的数据处理性能太低,于是引入了数据库,并慢慢成为了网站大后端的主流
apache无法处理动态请求,所以我们需要自己编写一个个的功能来处理这些动态请求(注意:这些动态请求有的需要查询数据库有的则不需要)
举例说明:
处理动态请求的伪代码,可以称之为web application,或者简web app 一:接收apache提交过来的用户请求,触发函数运行 二:连接数据库 三:操作数据库(增删改查) 四:根据获取的数据进行其他逻辑处理 五:返回给apache数据 六:关闭数据库
如下图:
问题一:编写web app时,需要深入研究apache工作的协议HTTP,这会严重影响了开发效率。
我们迫切需要在web server与web app之间定义一种标准,用来明细分工,web server对外提供一种标准,web app开发者只要遵循这个标准,那么后者就无需考虑web server到底是如何实现的了而可以专注web app的开发,这个标准就是网关协议
问题二:针对apache这款web server定制的代码,换成了另外的web server你的程序无法重用
在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 即通用网关接口(Common Gateway Interface), 是一种服务器和后端可执行程序之间的交互标准,或者说是web app应用程序(CGI程序)与Web服务器之间的接口标准。
原理:最原始的服务器,简单到就是访问文件目录,每次的请求都是请求加载目录下的文件。比如文档放在/var/www/html 目录下,访问 http://domain/index.html 其实就是请求 /var/www/html/index.html 文件。
CGI 通过服务器脚本(或者二进制文件),扩展了这个基础的『访问过程』。它利用程序的标准输入输出流,完成 HTTP 通信。每次请求的文本以标准输入流的形式进入服务器端的 CGI 程序,创建进程并执行,然后将运行结果通过进程的标准输出流输出作为响应。
eg:/usr/local/apache/htdocs/cgi-bin 是我们的 CGI 目录,当请求了 CGI 目录里的文件的时候(比如访问 http://domain/cgi-bin/printenv.pl ),服务器并不会返回这个文件,而会运行这个程序,然后将生成的内容返回给客户端。所以理论上,任何有输入输出能力的语言都可以用来写 CGI。
CGI脚本工作原理:
- 浏览器发送动态请求(通过HTML表单或者超链接)
- 服务端接收该请求,调用CGI脚本,产生一个CGI进程来处理该动态请求,结果返回给服务器
- 服务器将html返回给浏览器
CGI工作原理图:
优点
CGI 程序提供了很多静态网页无法实现的功能,比如加载数据、数据运算等等。早期的动态网页基本都是基于 CGI 实现的。
缺点
在 CGI 协议下,解析器的反复加载是性能低下的主要原因。每个发送到服务器的请求,都需要经过『启动进程、处理请求、结束进程』三个步骤,所以当访问量增大时,系统资源的开销也会增大,导致服务器性能下降甚至服务中断。
更甚至是,这种『一个请求一个进程』的模式意味着没有『状态』可言,导致很多资源无法复用,比如连接数据库、内存缓存、cpu消耗等等。
FastCGI:
FastCGI 是 CGI 的增强版本,用于减少 Server 与 CGI 应用之间的交互开销,从而使 Server可以同时处理更多的请求。
FastCGI与CGI 的 fork-and-execute 模式不同的是,FastCGI 以 Daemon 的形式运行,在初始化的时候会启动一个 FastCGI Server 然后长驻内存,处理一系列的请求。
FastCGI是一个可伸缩地、高速地在HTTP server和动态脚本语言间通信的接口。多数流行的HTTP server都支持FastCGI,包括Apache、Nginx和lighttpd等,同时,FastCGI也被许多脚本语言所支持,其中就有PHP。
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的工作流程:
Web Server启动时载入FastCGI进程管理器(PHP-CGI或者PHP-FPM或者spawn-cgi)
FastCGI进程管理器自身初始化,启动多个CGI解释器进程(可见多个php-cgi)并等待来自Web Server的连接。
当客户端请求到达Web Server时,FastCGI进程管理器选择并连接到一个CGI解释器。Web server将CGI环境变量和标准输入发送到FastCGI子进程php-cgi。
FastCGI子进程完成处理后将标准输出和错误信息从同一连接返回Web Server。当FastCGI子进程关闭连接时,请求便告处理完成。FastCGI子进程接着等待并处理来自FastCGI进程管理器(运行在Web Server中)的下一个连接。 在CGI模式中,php-cgi在此便退出。
优点
除了继承 CGI 原有的优点之外, FastCGI 还有以下特点:
- 业务分离:FastCGI 后端和 Web Server 运行在不同的进程中,后端的故障不会导致 Web Server 停止服务。
- 分布式计算:由于 FastCGI 服务器是可以独立运行的,所以 FastCGI 程序可以在服务器以外的主机上执行,并且接受来自其它服务器的请求。
- 多个可扩展角色:在 FastCGI 中,程序被赋予明确的角色,例如响应器角色、认证器角色、过滤器角色等等。
举例说明fastcgi工作原理:(依据nginx为例)
Nginx+FastCGI 的工作流程是这样的:
- 初始化 FastCGI 进程管理器,启动主进程和多个 CGI 子进程。主进程主要是管理子进程,同时还需要监听端口(例如9000端口);子进程则是处于等待连接的状态。
- 当请求到达服务器时,Nginx 通过 location 指令,将请求(例如以
php
为后缀的文件)分配到指定端口(例如9000端口)来处理。 - FastCGI 进程管理器选择并连接到一个子进程,服务器将环境变量和标准输入发送给子进程。
- 子进程接受请求并完成处理后,将标准输出和错误信息从同一连接返回给服务器。
- 子进程关闭连接,继续等待下一个请求。
工作原理图:
PHP-CGI是PHP自带的FastCGI管理器。PHP-CGI的不足: php-cgi变更php.ini配置后需重启php-cgi才能让新的php-ini生效,不可以平滑重启 直接杀死php-cgi进程php就不能运行了。(PHP-FPM和Spawn-FCGI就没有这个问题,守护进程会平滑从新生成新的子进程。)
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代码分析如下: 1.spawn-fcgi 首先create socket,bind,listen 3步创建服务器socket,(把这个socket叫做 fcgi_fd) 2.用dup2,把fcgi_fd 交换给 FCGI_LISTENSOCK_FILENO (FCGI_LISTENSOCK_FILENO数值上等于0,这是fastcgi协议当中指定用来listen的socket id) 3.执行execl ,replaces the current process image with a new process image. process image 进程在运行空间的代码段 很显然,Spawn-FCGI也是 pre-fork 模型,只是用了上古C语言编写,充满了N多 unix下暗黑编程技巧。 Spawn-FCGI功能很单一: 1.只管fork进程,子进程挂了,主进程仅仅log记录一次,根本不会重新fork。在2009年一段时间内,我曾经用spawn-fcgi部署php-cgi,当跑一段时间就会全挂掉,只能用crontab定时重启spawn-fcgi 不负责子进程中的网络IO,把socket放到指定位置就完了,接下来的事情由被spawn的程序处理 2.Spawn-FCGI是一个很早期的程序,瞻仰一下即可。另外有:1996年的一段代码:http://www.fastcgi.com/om_archive/kit/cgi-fcgi/cgi-fcgi.c,和spawn-fcgi一个风格
PHP-FPM是一个PHP FastCGI管理器,是只用于PHP的,可以在 http://php-fpm.org/download下载得到。PHP-FPM其实是PHP源代码的一个补丁,旨在将FastCGI进程管理整合进PHP包中。必须将它patch到你的PHP源代码中,在编译安装PHP后才可以使用。FPM(FastCGI 进程管理器)用于替换 PHP-CGI 的大部分附加功能,对于高负载网站是非常有用的。它的功能包括: 1.支持平滑停止/启动的高级进程管理功能; 2.可以工作于不同的 uid/gid/chroot 环境下,并监听不同的端口和使用不同的 php.ini 配置文件(可取代 safe_mode 的设置); 3.stdout 和 stderr 日志记录; 4.在发生意外情况的时候能够重新启动并缓存被破坏的 opcode; 5.文件上传优化支持; 6.“慢日志” – 记录脚本(不仅记录文件名,还记录 PHP backtrace 信息,可以使用 ptrace或者类似工具读取和分析远程进程的运行数据)运行所导致的异常缓慢; 7.fastcgi_finish_request() – 特殊功能:用于在请求完成和刷新数据后,继续在后台执行耗时的工作(录入视频转换、统计处理等); 8.动态/静态子进程产生; 9.基本 SAPI 运行状态信息(类似Apache的 mod_status); 10.基于 php.ini 的配置文件。
WSGI:
什么是WSGI?
Web服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口,最初是为 Python 量身定做。
自从WSGI被开发出来以后,许多其它语言中也出现了类似接口。WSGI是作为Web服务器与Web应用程序或应用框架之间的一种低级别的接口,以提升可移植Web应用开发的共同点。WSGI是基于现存的CGI标准而设计的。
有了WSGI,你就不用去考虑,服务器程序的具体实现,应用程序获得了很好的适用性。比如一个云平台提供了对 WSGI 接口的支持,那么,只要应用是基于 WSGI 的,就可以直接跑起来。其实keystone就是一款python开发的基于WSGI标准的app。
什么是WSGI中间件?
基于WSGI 的设计哲学,我们可以写一些对 server 和 application 都兼容的模块,即WSGI中间件(middleware)。所谓的 WSGI 中间件同时实现了API的两方,因此可以在WSGI服务和WSGI应用之间起调解作用:从WSGI服务器的角度来说,中间件扮演应用程序,而从应用程序的角度来说,中间件扮演服务器。
WSGI中间件的功能与好处?
WSGI中间件可以完成比如缓存、字符编码转换、根据 url 做应用 routing 等功能。
这种设计模式,是 WSGI 降低了 server 和 application 耦合度之后的产物,同时,它从另一个角度大大提升了设计的灵活性。
WSGI的处理模式
WSGI将 web 组件分为三类: web服务器,web中间件,web应用程序
wsgi基本处理模式为 : WSGI Server -> (WSGI Middleware)* -> WSGI Application 。
在处理一个WSGI请求时,服务器会为应用程序提供环境资讯及一个回呼函数(Callback Function)。当应用程序完成处理请求后,透过前述的回呼函数,将结果回传给服务器。
wsgi server可以理解为一个符合wsgi规范的web server,接收request请求,封装一系列环境变量,按照wsgi规范调用注册的wsgi app,最后将response返回给客户端。文字很难解释清楚wsgi server到底是什么东西,以及做些什么事情,最直观的方式还是看wsgi server的实现代码。以python自带的wsgiref为例,wsgiref是按照wsgi规范实现的一个简单wsgi server。它的代码也不复杂。
- 服务器创建socket,监听端口,等待客户端连接。
- 当有请求来时,服务器解析客户端信息放到环境变量environ中,并调用绑定的handler来处理请求。
- handler解析这个http请求,将请求信息例如method,path等放到environ中。
- wsgi handler再将一些服务器端信息也放到environ中,最后服务器信息,客户端信息,本次请求信息全部都保存到了环境变量environ中。
- wsgi handler 调用注册的wsgi app,并将environ和回调函数传给wsgi app
- wsgi app 将reponse header/status/body 回传给wsgi handler
- 最终handler还是通过socket将response信息塞回给客户端。
中间件:
Middleware 是一个比较特殊的存在,它是夹在二者之间的,对于 Server 端而言它是个 Application ,而对于 Application 而言它就是 Server 端。
它可以实现以下功能:
- 重写环境变量,根据目标 URL,将请求消息路由到不同的应用对象。
- 允许在一个进程中同时运行多个应用程序或应用框架。
- 负载均衡和远程处理,通过在网络上转发请求和响应消息。
- 进行内容后处理,例如应用 XSLT 样式表。
优点
WSGI 将请求的工作通过异步回调进行拆解,可以很方便的在一个线程空间里同时处理多个请求。
另外,方便进行负载均衡和请求转发,不会造成后端应用阻塞。
Application
Application 会处理请求并通过回调函数将结果返回给 Server。
和 Serve 对应,一个标准的 Application 接受两个参数:
- environ:一个包含所有 HTTP 请求信息的 dict 对象
- start_response:一个发送 HTTP 响应的函数
Server
Server 端从规定的输入中获取 Request 数据,然后把环境变量(environ)和回调函数(start_response)传给 Application
uWSGI
uWSGI 项目旨在为部署分布式集群的网络应用开发一套完整的解决方案。uWSGI主要面向web及其标准服务,已经成功的应用于多种不同的语言。由于uWSGI的可扩展架构,它能够被无限制的扩展用来支持更多的平台和语言。目前,你可以使用C,C++和Objective-C来编写插件。项目名称中的“WSGI”是为了向同名的Python Web标准表示感谢,因为WSGI为该项目开发了第一个插件。uWSGI是一个Web服务器,它实现了WSGI协议、uwsgi、http等协议。uWSGI,既不用wsgi协议也不用FastCGI协议,而是自创了一个uwsgi的协议,uwsgi协议是一个uWSGI服务器自有的协议,它用于定义传输信息的类型(type of information),每一个uwsgi packet前4byte为传输信息类型描述,它与WSGI相比是两样东西。据说该协议大约是fcgi协议的10倍那么快。
- uWSGI的主要特点如下:
- 超快的性能。
- 低内存占用(实测为apache2的mod_wsgi的一半左右)。
- 多app管理。
- 详尽的日志功能(可以用来分析app性能和瓶颈)。
- 高度可定制(内存大小限制,服务一定次数后重启等)。
第五:网关协议与keystone
keystone本质就是python开发的一款基于wsgi的app,社区提倡的部署方法:
apache(wsgi)+keystone
nginx(uwsgi)+keystone