原文地址:http://www.fastcgi.com/devkit/doc/fastcgi-whitepaper/fastcgi.htm
一 前言
随着web的广泛应用,对动态内容的需求也越来越迫切。CGI提供了一种解决方案,但是CGI有一个最大的问题就是无法满足高密度请求环境下的性能需求。Open Market为了解决这个问题从而开发了FastCGI。
FastCGI是一个快速,开源,安全的web服务器接口,它是兼容CGI的API,但是它解决了CGI中性能问题,
CGI(Common Gateway Interface)
CGI是一个标准的web服务器应用程序接口,它第一次是在NCSA服务器中实现,它具有一下特点:
- 简单:和编程语言无关:CGI应用程序可以利用任意编程语言进行开发,C,JAVA,Perl
- 独立进程:CGI的解析是进程独立的。每一个请求开始通过创建一个进程,处理完以后,进程就结束。如果进程出现bug,不会影响web服务器的运行
- 开放性标准:在每一个web服务器都实现了CGI。
- 体系结构独立:CGI和特定的服务器体系结构无关(单线程,多线程都无所谓)
CGI也有很多缺陷,其中最大的缺陷是性能问题:针对每一个请求,创建一个新的进程。当请求结束就终止进程。在高密度请求的环境下,这种反复性创建进程使得的整体性能很差。
CGI有另外一个缺点:CGI只扮演简单的“回应”角色,它针对每一个请求,生成一个回应,返回给客户端。CGI程序无法和Web服务器其他层次进行“通信”,比如不支持认证,日志等功能。
服务端APIs
为了解决CGI程序的性能问题,服务器厂商针对每一个服务器开发出相应的服务端API,通过该API可以实现与CGI相似的功能。最出名的有NSAPI(Netscape)和ISAPI(Microsoft)。Apache环境下有也相应的服务端API。通过服务端API,应用程序直接和web服务器进行交互,它的性能明显快于CGI应用程序。该应用程序直接运行在服务器端,并且永久存在,不需要像CGI那样反复创建进程。另外web服务器APIs提供更加多的功能,比如权限控制,能够操纵服务器日志文件,可以在多个层次处理服务器各种类型的请求。
尽管服务端API有以上优点,但是它也有以下缺点:
- 复杂性:服务端APIs有一个很高学习台阶,增加实现和修改的代价。
- 编程语言不独立:应用程序必须针对特定服务端APIs采用特定适应的编程语言。
- 进程不独立:因为服务器进程是运行在web服务器的进程空间,应用程序和服务器之间关联太强,任何一端有bug,都会导致另外一端奔亏。
- 特定服务器依赖性:开发出来的应用程序过度依赖服务器软件和版本。
- 和服务器体系结构相绑定:应用程序和服务器共用体系结构:如果服务器是多线程,那么应用程序必须考虑线程安全性。如果服务器是单线程的,那么多线程的应用程序无法得到性能上得到提高,如果服务器改变其体系结构,那么以前开发的应用程序也需要进行改变。
FastCGI
FastCGI结合上面CGI和服务器APIs的优点,它和CGI一样,FastCGI应用程序运行在分开的独立的进程。它还有以下的优点:
- 性能:FastCGI进程是持久的,它可以重复利用来处理多次web请求。这一点解决了CGI重新的创建和注销进程而带来性能问题。
- 和CGI之间的移植和兼容功能:利FastCGI API可以很轻易的把已经存在的CGI程序移植过来。并且利用FastCGI API开发出现的应用程序可以当着CGI程序进行运行,并且兼容老的服务器。
- 语言独立:和CGI程序一样,FastCGI应用程序可以利用任意编程语言进行编写。
- 进程独立:FastCGI应用程序和服务器之间是进程独立的,应用程序的奔亏不会影响服务器的正常运行。并且应用程序不可以从web服务器中得到任何安全相关的信息,比如session keys
- 和特定服务器无关:FastCGI支持大部分的服务器,包括Apache,lighttpd等。
- 体系结构独立:FastCGI应用程序和特定服务器体系结构独立。
- 支持分布式运行:fastCGI支持远程运行应用程序,在分布式负载均衡和管理中,该功能比较实用。
下面的内容将会详细介绍FastCGI的接口,协议,开发类库。
二 FastCgi接口
FastCGI提供了和CGI类似的功能,为了更好的理解FastCGI,我们首先必须弄到CGI接口,基本的CGI请求处理流程如下:
- 对于每请求,web服务器创建一个新的进程,并且进程进行自我初始化。
- web服务器通过环境变量向CGI程序传递请求信息(包括远程请求主机信息,HTTP头部等信息)
- web服务器通过标准的IO输入向CGI程序传递客户端输入(比如用户相关的HTML的表达等信息)
- CGI程序通过标准IO输出向客户端写返回信息,web服务器通过标准错误输出进行输出错误信息。
- CGI进程退出,请求完成。
FastCGI和CGI比较相似,但是有下面两点不同:
- FastCGI进程是持久的。每一个进程,处理完请求以后,将会等待下一个请求,而不是结束该进程。
- CGI是通过操作系统的环境变量和pipes管道进行数据的传输,而FastCGI通过单一的全双工连接来复用系统环境变量,标准/错误输入输出。因此FastCGI程序可以通过TCP连接来实现web服务器和FastCGI程序之间的通信,从而使其可以运行在远程机器上。
单线程结构下的FastCGI进程处理请求的过程如下:
- web服务器启动时候,创建一个FastCGI进程池来处理后续的所有请求,该进程池中保护多个进程,该进程可以在启动时候创建,也可以通过命令的方式进行创建。
- FastCGI完成自己初始化,并等待从web服务器来的新的连接请求
- 当来了一个客户端请求,web服务器和FastCGI之间创建一个连接,web服务器通过该连接向FastCGi程序发生CGI环境变量和标准的输入。
- FastCGI进程处理完请求,把标准的输出信息和错误信息通过相同的连接发送到web服务器
- FastCGI关闭该连接,请求结束,进程继续等待后续的连接接
FastCGI程序可以运行在本地或者远程,运行本地时,服务器通过全双工管道来连接FastCGI应用程序。对于远程,服务器使用TCP连接。FastCGI程序可以是单线程或多线程,对于单线程程序,web服务器创建一个FastCGI进程池来处理客户端请求。该进程池的大小是可以配置的。对于多线程FastCGI程序可以同时接受多个web服务器请求来同时处理该请求。
远程FastCGI
利用FastCGI来适应防火墙的设置
现实中有这样一个挑战:如果应用程序运行在外部web服务器上,但是它需要内部数据库上数据或者应用。下图显示一个典型的架构,外部服务器在防火墙的管理下限制操作内部服务器的数据和应用程序:
如果使用CGI和服务端APIs,而应用程序运行在web服务器。此时意味着服务器管理员必须复制所需的数据库信息在系统上托管的Web服务器(而这在要求不影响防火墙的安全性的前提下,是很难做到自动化的管理)。或者,管理员可以建立一座“桥梁”,允许通过Web服务器访问内部数据库和应用程序(这实际上是重新发明了远程FastCGI)。
通过简单配置远程FastCGI,应用程序可以运行在内部服务器上,当使用适当的防火墙配置和审计,这种方法提供了一个安全,高性能,可伸缩的方式,使内部到外部网络的应用程序和数据。
通过远程FastCGI来实现负载均衡
对于资源密集性的CGI和服务的API程序,web服务器很快就成为整体吞吐量的瓶颈。最常见解决这个问题的办法是购买一个更大更快的web服务器或者把web网站分布到多个服务器上(需要改变原先的链接)。
管理员可以通过配置远程FastCGI,对于那些资源密集性的应用程序可以移出主web服务器,并且通过该办法不需要改变原先内容的连接地址,管理员可以通过多个低廉的服务器来运行FastCGI应用程序。
远程FastCGI相关安全问题
对于远程FastCGI程序来说,有两个安全问题:认证和资料保密。FastCGI必须只接受来自信任的的服务器连接(API中提供了对支持IP的验证功能)。并且未来版本将会提供SSL和PCT安全链接来保证数据传输的安全。
FastCGI协议
本节主要介绍一下web服务器和FastCGI应用程序之间的连接的通信协议。大部分应用程序开发人员其实不需要知道通信协议仅仅通过使用FastCGI API来完成程序开发。
FastCGI通信协议使用一个简单的封包记录格式:
其中Protocol Version指定当前协议的版本。Record Type指定该记录的类型(详细见下面表格)
FCGI_PARAMS | 传送名称/值组合的资料,如环境变数 |
---|---|
FCGI_STDIN | 传送标准输入资料(从伺服器到应用程式) |
FCGI_DATA | 传送过滤资料到应用程式 |
FCGI_STDOUT | 传送标准输出资料(从应用程式到伺服器) |
FCGI_STDERR | 传送标准错误资料(从应用程式到伺服器) |
FCGI_END_REQUEST | 结束(应用程式及伺服器皆可用) |
介绍的有点简单吗!!!后面去详细看看,红色标记一下
三 FastCgi应用功能
对于CGI程序来说,它其中一个缺陷就是它仅仅提供Responder回应者的功能。而FastCGI提供了一个功能扩展包括下面三个不同应用功能:
- Responder回应者:这个是FastCGI最基本的功能,和CGI兼容。
- Filter过滤器:FastCGI应用程序可以在把内容送回给client之前进行过滤处理。
- Authorizer认证:FastCGI提供一个对应用请求的权限控制。
在未来的版本将会提供其他的功能,比如日志功能。下面只是简单介绍,后面去分别写写相应功能的程序,红色标记一下
回应者
过滤器
- 未知格式的转换
- 动态内容(比如文档中包含嵌入SQL语句,或者动态插入广告)
- 提供一个标准模板:头部,背部,和背景
认证
- 通过用户名和密码来进行权限控制
- 复杂的访问策略,比如基于时间的访问控制
- 智能卡认证领域
- 动态重定向,根据认证配置文件来动态重定向用户的请求
四 FastCGI应用程序库
Open Market开发一套FastCGI API实现了FastCGI协议,该库使得FastCGI开发人员可以和CGI程序一样,轻松书写FastCGI程序。
应用程序库提供了一个替代方案来替代基于C语言标准的IO运行时类库,比如printf()和gets()。该类库把标准的输入,输出,错误输出转换到FastCGI通信协议,对于其他的请求由操作系统的标准IO进行处理。
使用FastCGI应用程序库有以下几个好处:
- 开发人员不需要学习新的API来开发FastCGI应用程序。
- 已经存在的CGI应用程序可以很容易移植到FastCGI中
- 看到什么perl。不关心,不翻译了。
下面是一个简单的FastCGI程序:
#include <fcgi_stdio.h>
void main(void)
{
int count = 0;
while(FCGI_Accept() >= 0) {
printf("Content-type: text/html\r\n");
printf("\r\n");
printf("Hello world!<br>\r\n");
printf("Request number %d.", count++);
}
exit(0);
}
该程序返回一个"Hello Word"给客户端,并且包含一个该FastCGI处理的计数器,并且显示在每一次的请求返回结果里面。
fcgi_stdio.h头文件提供一个C IO标准运行库的FastCGI替代运行时。函数FCGI_Accept()接受一个新的来自web服务器的请求。
CGI程序移植
在设计FastCGI应用程序库时,追求更易的CGI移植。很多应用程序可以通过添加简单的循环,并重新编译从而把CGI转化为FastCGI应用程序。每一个FastCGI包含一个初始段和一个请求循环段:
Initialize application;
while(FCGI_Accept() >= 0) {
Process request;
}
为了更加容易移植,利用FastCGI库开发的程序可以根据它被调用的方式,来确定其是以CGI或者FastCGI程序的类型来运行。类库可以检查执行环境,自动选择FastCGI或者标准的IO进行运行。
在转换以后,程序员需要优化FastCGI程序来寻求最优的性能:
- 修复资源泄漏问题。大部分CGI程序不需要管理内存或者关闭文件,因为请求结束,进程关闭以后,会自动进行相应的资源回收。在转化以后需要进行资源泄漏问题的修复。
- 修复由于状态保留的而导致的问题。每一个应用程序必须确保它的每一个请求的状态不会影响后面的请求。
- 功能组合。CGI应用程序建议把功能分散为很多个小的应用程序,一个功能一个进程,这样可以减少CGI程序加载时候的消耗。而在FastCGI程序中,建议把相应功能的程序放到同一个程序中,从而减少需要管理的进程的数目,和充分利用进程的共有资源。
五 FastCGI性能分析
FastCGI程序有多快?该问题主要依赖应用程序。本节讨论一个现实问题的处理的性能,并且给出一个FastCGI应用程序加速方案。
FastCGI vs CGI
Static file
|
21ms + 0.19ms per Kbyte
|
FastCGI
|
22ms + 0.28ms per Kbyte
|
CGI
|
59ms + 0.37ms per Kbyte
|
CGI | 59ms + 50ms + (0.37ms)(5) = 111ms |
FastCGI | 22ms + (0.28ms)(5) = 23ms |
六 总结
今天,我们需要一个快速,开发,可维护,简单,稳定,安全的平台,其中FastCGI的设计满足了这个要求,并且在CGI上提供一个逻辑上的扩展,这是的开发者可以很容易把以前的CGI程序移植到现在的平台。