主程的晋升攻略(6):CGI和FastCGI
消息经过网络传输,到达了服务器端,最常见的服务器是Web服务器,做PHP的同学都知道FastCGI模式的PHP比普通PHP更高效,这篇就聊聊其中的原理。
古老但常见的CGI
Web服务器能解析HTTP请求,返回静态资源(HTML页、图片等),但要输出动态内容,必须得PHP/C#/Ruby/Java/Python/C/C++这些外部程序来实现。
早期有个技术叫CGI(Common Gateway Interface,通用网关接口),是用于Web服务器和外部程序之间传输数据的一种标准。一个简单的CGI程序(C++语言)如下:
#include <stdio.h> #include <stdlib.h> int main() { printf("Content-type: text/html\r\n\r\n"); printf("your name is:%s\n", getenv("QUERY_STRING")); return 0; }
浏览器访问这个CGI程序,就会显示:your name is:name=xxx
CGI规定了Web服务器如何和CGI程序之间传输数据,具体过程大体是这样:
1、Web服务器收到的请求信息后,启动CGI程序(apache是fork进程exec CGI程序);
2、Web服务器通过环境变量和标准输入把请求信息传递给CGI程序;
3、CGI程序执行业务逻辑后,通过标准输出和标准错误把响应数据返回给Web服务器,CGI程序exit;
4、Web服务器再组织成HTTP响应包发给浏览器。
在上面的例子中,第一行printf是输出HTTP头(还记得HTTP Header和Body是用\r\n\r\n分割的么?),getenv("QUERY_STRING")是从环境变量获取URL,printf是通过标准输出返回内容。
Web服务器会把哪些信息通过环境变量传递给CGI程序?常用的有这些:
- CONTENT_LENGTH :向标准输入发送的数据的字节数(POST)
- QUERY_STRING:实际存放发送给CGI程序的数据(GET)
- REQUEST_METHOD:传送数据所用的CGI方法(GET或POST)
- HTTP_COOKIE:cookie值
- REMOTE_ADDR:用户IP
- SCRIPT_NAME:请求的CGI
可以看到CGI只是一种标准,可以用任何一种语言编写CGI程序,只要这种语言具有标准输入、标准输出和环境变量,比如:C/C++,perl,PHP、ruby。按照CGI标准要求,就能和Web服务器交互起来。
FastCGI应运而生
CGI是通过环境变量/标准输入、标准输出/标准错误来传输数据,运行性能比较低,主要有两点:
1、每个请求都需要Web服务器去fork出CGI程序,频繁fork进程比较耗时
2、CGI程序每次都是从头运行,读配置、连接其他服务都得重新来,也比较耗时
FastCGI是对CGI的改进,FastCGI模式下,Web服务器和FastCGI程序传输数据的过程大体是:
1、Web服务器收到的请求信息后,按FastCGI协议把请求信息通过socket发给FastCGI程序;
2、FastCGI程序执行业务逻辑后,通过socket把响应数据返回给Web服务器,FastCGI程序不exit;
3、Web服务器再组织成HTTP响应包发给浏览器。
对比CGI的通过,可以发现主要是少了每次fork的过程,并且用socket来传输数据,这是FastCGI接口更高效的原因。
FastCGI有这些特点:
- FastCGI程序常驻内存,启动后可以反复处理请求
- FastCGI 就是进程池/线程池模型的通用同步服务器框架
FastCGI程序处理请求后不会退出,可以反复处理请求,那么在启动后就把配置解析、与其他后台的连接建立好,不用每次请求时搞一边,自然更快了。
至于这个FastCGI内部如何实现进城池/线程池,就是FastCGI进程管理器(FastCGI引擎)的事情了。C/C++ FastCGI常用apache的mod_fastcgi模块,PHP常用spawn-fcgi和PHP-FPM。