从CGI到FastCGI到PHP-FPM
从CGI到FastCGI到PHP-FPM
背景
笔者在学习这几个名词的时候,也是被百度到的相关文章迷惑。涉及到的主要名词包括
1. CGI协议
2. CGI脚本
3. PHP-CGI
4. FastCGI协议
5. PHP-FPM
要真正理解这些名词,如果我们硬生生的解释,也很难记住。我们可以从web服务器开发的历程来看,看看他们为什么会出现,以及他们解决了什么问题。
早些年的简单服务器
早些年的服务器很简单,你访问一个网站,比如www.helloworld.com
,网站只返回你一个静态HTML页面。为了简单起见,我们假设网站值返回hello标题,这样流程可以用下图表示
这时候server是采用C语言编写的,基本上一个简的C脚本就可以了,把这个服务器脚本命名为hello_server.c
,代码可以到github上下载
在Linux环境中使用gcc编译hello_server.c
vagrant@kfz:~$ gcc hello_world.c
然后采用curl
工具测试
vagrant@kfz:~$ curl "127.0.0.1:8887"
GET / HTTP/1.1
User-Agent: curl/7.49.1
Host: 127.0.0.1:8887
Accept: */*
Hello World
这里我们的重点不在HTTP响应的格式上,所以我们直接输出了Hello World
,如果是请求静态页面,我们也是一样的思路,读取静态文件的内容然后返还给客户端。
思考:当Web时代越来越火爆,我们希望Web服务器有更多的功能,比如写博客,聊天,等等。同时,越来越多的不同领域的开发者想在web时代大显身手。很多服务器开发者发现有了以下缺点
#服务器功能方面
Web服务器功能会随着这种逻辑的增长而增长,服务器会变的不专一
#语言支持方便
越来越多的PHP,Python开发者想开发服务端程序,编写更多的功能,发现自己的语言无从下手
CGI协议与CGI程序
什么是CGI协议和CGI程序
既然Web服务器想做的专一,但又要支持Web的飞速发展,同时还想让其他语言开发者也能加入Web开发。所以,就出了一种方式,Web服务器和其他领域的开发者拟定一条协议,在保证遵守协议的基础上,剩下的可以自由发挥。没错,这条协议就是CGI协议
,协议的内容可以查看,而实现这个协议的脚本叫做CGI程序
。CGI协议规定了需要向CGI脚本设置的环境变量和一些其他信息,CGI程序完成某一个功能,可以用PHP,Python,Shell或者C语言编写。
这样的好处Web开发更加开放了,可以用任何开发者擅长的语言开发Web程序。比如,我是一个PHP开发者,用PHP有很多现成的库访问第三方服务,入MySQL,Memcache等,但是这些第三方服务使用C语言接入还是比较麻烦的。有了CGI协议,我们的Web处理流程可以变成下图这样
实现一个PHP版的CGI程序
一般情况下,我们把CGI程序放在cgi-bin目录下面,新建PHP版CGI处理程序cgi-bin/get_user.php
,我们的服务器程序还是使用简单的hello_server.c
。
目标:用户访问URL127.0.0.1:8887/cgi-bin/get_user.php?id=1
的的时候输出用户ID为1的用户信息
实现:很显然,我们要解决两个问题
1. 在服务器程序hello_server.c中执行get_user.php文件
2. 服务器程序hello_server.c向get_user.php中传递请求信息(id=1)
第一个问题我们使用C库还是popen
来运行php脚本,第二个问题在CGI协议中规定了我们的解决方案。首先需要将请求参数放在环境变量中,其次,环境变量的名字也规定好了。这里列举一些CGI协议规定的常用的环境变量,这里只列举一些,全部的内容可以协议明细
变量名 | 描述 |
---|---|
CONTENT_TYPE | 这个环境变量的值指示所传递来的信息的MIME类型。目前,环境变量CONTENT_TYPE一般都是:application/x-www-form-urlencoded,他表示数据来自于HTML表单 |
HTTP_USER_AGENT | 提供包含了版本数或其他专有数据的客户浏览器信息 |
QUERY_STRING | 如果服务器与CGI程序信息的传递方式是GET,这个环境变量的值即使所传递的信息。这个信息经跟在CGI程序名的后面,两者中间用一个问号'?'分隔 |
REQUEST_METHOD | 提供脚本被调用的方法。对于使用 HTTP/1.0 协议的脚本,仅 GET 和 POST 有意义 |
所以,关于服务端怎么向CGI程序传递请求信息的问题就可以解释了。在服务端接收到用户请求的时候需要按照CGI协议通过putenv
设置环境变量,然后PHP程序也是按照CGI协议解析环境变量(PHP中使用$_SERVER即可)。
程序的实现,可以在这里下载
最后需要说明的,当服务器执行php cgi-bin/get_user.php
的时候,实际上是使用php的命令行模式执行的,因为PHP已经为我们封装好了环境变量,所以我们只需要从$_SERVER
中就可以获取我们需要的环境变量。这里只为了说明问题,实际上PHP的sapi里面有单独实现cgi接口。当然你也可以用shell实现,shell的话是直接获取环境变量
CGI程序的缺点
CGI工作原理:每当客户请求CGI的时候,WEB服务器就请求操作系统生成一个新的CGI解释器进程,CGI进程则处理完一个请求后退出,下一个请求来时再创建新进程。我们知道,执行一个PHP程序的必须要先解析php.ini文件,然后模块初始化等等一系列工作,每次都反复这样非常浪费资源。当然,这样在访问量很少没有并发的情况也行。可是当访问量增大,并发存在,这种方式就不适合了。这也是CGI程序一个致命的缺点。
FastCGI协议和php-cgi
FastCGI协议
既然上面提到了CGI程序的一个致命缺陷,所以在CGI协议的基础上,又设计了FASTCGI协议
,协议的内容可以查看,概括一下,主要做了以下改变
1. FastCGI被设计用来支持常驻(long-lived)应用进程,减少了fork-and-execute带来的开销
2. FastCGI进程通过监听的socket,收来自Web服务器的连接,这样FastCGI进程可以独立部署
3. 服务器和FastCGI监听的socket之间按照消息的形式发送环境变量和其他数据
所以,我们称实现了FastCGI协议
的程序为FastCGI程序
,在php中的sapi/cgi/php-cgi
实现了这个协议,虽然它的名字取名为php-cgi,但其实是支持FacsCGI协议的。所以,实现了FastCGI协议的服务器和FastCGI程序的交互方式如下图所示
PHP中FastCGI使用
可能很少人用过php-cgi,因为目前大家都使用php-fpm(先不讨论php-fpm)。这里介绍一下php-cgi的使用。
1.php-cgi如何启动监听socket
php-cgi可执行程序为编译后的php目录下面的sapi/cgi/php-cgi
。通过-b
参数指定需要监听的ip和端口即可,比如我们想绑定本机的9004端口
shell> ./php-cgi -b 127.0.0.1:9004
2.如何启动多个FastCGI进程
这里需要使用PHP_FCGI_CHILDREN
环境变量表示派生多少个子进程,我们可以写一个shell来启动php-cgi,点击可以下载这个shell文件。注意替换成自己的cgi路径后再使用
3.通过shell脚本启动FastCGI管理器
执行start.sh
脚本之后,可以查看到启动了多个FastCGI进程
shell> ps aux | grep php-cgi | grep -v grep
vagrant 6785 0.0 0.0 1936 524 pts/3 S 01:07 0:00 sh -c /home/vagrant/php-5.5.10/sapi/cgi/php-cgi -b 127.0.0.1:9004
vagrant 6792 0.0 0.3 13760 3188 ? Ss 01:07 0:00 /home/vagrant/php-5.5.10/sapi/cgi/php-cgi -b 127.0.0.1:9004
vagrant 6793 0.0 0.1 13760 1384 ? S 01:07 0:00 /home/vagrant/php-5.5.10/sapi/cgi/php-cgi -b 127.0.0.1:9004
vagrant 6794 0.0 0.1 13760 1384 ? S 01:07 0:00 /home/vagrant/php-5.5.10/sapi/cgi/php-cgi -b 127.0.0.1:9004
vagrant 6795 0.0 0.1 13760 1384 ? S 01:07 0:00 /home/vagrant/php-5.5.10/sapi/cgi/php-cgi -b 127.0.0.1:9004
vagrant 6796 0.0 0.1 13760 1384 ? S 01:07 0:00 /home/vagrant/php-5.5.10/sapi/cgi/php-cgi -b 127.0.0.1:9004
vagrant 6797 0.0 0.1 13760 1384 ? S 01:07 0:00 /home/vagrant/php-5.5.10/sapi/cgi/php-cgi -b 127.0.0.1:9004
vagrant 6798 0.0 0.1 13760 1384 ? S 01:07 0:00 /home/vagrant/php-5.5.10/sapi/cgi/php-cgi -b 127.0.0.1:9004
vagrant 6799 0.0 0.1 13760 1384 ? S 01:07 0:00 /home/vagrant/php-5.5.10/sapi/cgi/php-cgi -b 127.0.0.1:9004
vagrant 6800 0.0 0.1 13760 1384 ? S 01:07 0:00 /home/vagrant/php-5.5.10/sapi/cgi/php-cgi -b 127.0.0.1:9004
4.和Nginx配合测试
在Nginx配置文件中加上这一段
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9004;
include fastcgi.conf;
}
重启nginx之后就可以测试nginx访问php了。
php-cgi的的缺点
php-cgi实现的已经很完美了,但是我们的需求总是有点苛刻,导致它暴露了一下问题
- 当我们更改配置文件后,php-cgi显然无法平滑重启
- 我们fork的进程个数和请求量正比,请求繁忙时,fork进程多,动态调整,显然php-cgi没做到
spawn-fcgi和PHP-FPM
既然上面提及php-cgi实现的FastCGI问题官方没有解决。那自然有第三方做这个事情,我们可以使用Lighttpd的spawn-fcgi来管理php-cgi进程。注意,这里的spawn-fcgi是进程管理器,只是管理实现FastCGI协议的php-cgi,这个的安装和使用方式可以参照鸟哥的博客
还有一个做的比较好的,php-fpm,以前php-fpm并没有纳入php安装包文件中,只是在它的卓越表现,得到了越来越多的人认可,后面就被纳入了官方默认安装包文件中。php-fpm是从5.3开始才进入PHP源代码主干的,可以独立运行,不依赖php-cgi,换句话说,他自己实现了FastCGI协议。
所以,spawn-fcgi和PHP-FPM不是同一个东西,前者是进程管理器,后者却实现FastCGI协议并且支持进程平滑重启
从CGI到FastCGI到PHP-FPM的更多相关文章
- 网关协议学习:CGI、FastCGI、WSGI、uWSGI
一直对这四者的概念和区别很模糊,现在就特意梳理一下它们的关系与区别. CGI CGI即通用网关接口(Common Gateway Interface),是外部应用程序(CGI程序)与Web服务器之间的 ...
- CGI 和 FastCGI 协议的运行原理
目录 介绍 深入CGI协议 CGI的运行原理 CGI协议的缺陷 深入FastCGI协议 FastCGI协议运行原理 为什么是 FastCGI 而非 CGI 协议 CGI 与 FastCGI 架构 再看 ...
- 简单了解下CGI、FastCGI和php-fpm的概念和区别和运行原理
什么是CGI? CGI(Common Gateway Interface),公共网关接口,它是Web服务器与外部应用程序(CGI程序)之间传递信息的接口标准.通过CGI接口,Web服务器就能够获取客户 ...
- 网关协议:CGI、FastCGI、WSGI
CGI就像是一座桥,把网页和WEB服务器中的执行程序连接起来,它把HTML接收的指令传递给服务器的执行程序,再把服务器执行程序的结果返还给HTML页. CGI CGI即通用网关接口(Common Ga ...
- 【转】网关协议学习:CGI、FastCGI、WSGI、uWSGI
一直对这四者的概念和区别很模糊,现在就特意梳理一下它们的关系与区别. CGI CGI即通用网关接口(Common Gateway Interface),是外部应用程序(CGI程序)与Web服务器之间的 ...
- 【转】CGI 和 FastCGI 协议的运行原理
介绍 深入CGI协议 CGI的运行原理 CGI协议的缺陷 深入FastCGI协议 FastCGI协议运行原理 为什么是 FastCGI 而非 CGI 协议 CGI 与 FastCGI 架构 再看 Fa ...
- PHP面试经常被问cgi、fastcgi、php-fpm、mod_php的区别
cgi.fastcgi.php-fpm.mod_php cgi cgi是公共网关接口,用户通过浏览器来访问执行再服务器上的动态程序,CGI是Web 服务器与CGI程序间传输数据的标准.准确来说是一种协 ...
- CGI与FastCGI nginx+PHP-FPM
本文转载自CGI与FastCGI 1.当我们在谈到cgi的时候,我们在讨论什么 最早的Web服务器简单地响应浏览器发来的HTTP请求,并将存储在服务器上的HTML文件返回给浏览器,也就是静态html. ...
- CGI与FastCGI
当我们在谈到cgi的时候,我们在讨论什么 最早的Web服务器简单地响应浏览器发来的HTTP请求,并将存储在服务器上的HTML文件返回给浏览器,也就是静态html.事物总是不 断发展,网站也越来越复杂, ...
- php CGI、Fastcgi、PHP-FPM的详细介绍与之间的关系
以下PHP CGI.Fastcgi.PHP-FPM的一些信息归纳和汇总----->详细介绍与之间的关系 一:CGI是干嘛的?CGI是为了保证web server传递过来的数据是标准格式的 web ...
随机推荐
- 分享知识-快乐自己:Maven 无法加载 Oracle 数据库驱动源
由于Oracle授权问题,Maven3不提供Oracle JDBC driver,为了在Maven项目中应用Oracle JDBC driver,必须手动添加到本地仓库. 手动添加到本地仓库需要本地有 ...
- jQuery与javascript库
[jquery-javascript库] 为了简化javascript的开发,诞生了javascript程序库,他封装了很多预定的对象和实用函数.下面是几种流行的javascript程序库:proto ...
- PHP不用第三变量交换2个变量的值的解决方法
以前做过一道php面试题是这样的:不使用第三个变量实现交换两个变量的值.一般都是借助第三个中间变量来实现原来两个变量的值交换,但是这道题却要求不能使用中间变量,这对于初学者来说也算是一个难题了.网上找 ...
- perl: warning: Falling back to the standard locale ("C").
/********************************************************************************** * perl: warning: ...
- H264视频编码成MP4文件
firehood的专栏 Wince嵌入式开发 目录视图 摘要视图 订阅 赠书 | AI专栏(AI圣经!<深度学习>中文版) 每周荐书:Kotlin.分布式.Keras ...
- 表达式(exp)
题目大意 给定一个逻辑表达式,求每一个数满足$\in[1,n]$的使的表达式为真的方案数. 题解 题目限制较奇怪且数据范围较小,所以可以考虑直接暴力. 考虑枚举每一个变量一共出现了$k$种数值,再枚举 ...
- HDU3037Saving Beans(组合数+lucas定理)
Problem Description Although winter is far away, squirrels have to work day and night to save beans. ...
- ACM学习历程—ZOJ 3777 Problem Arrangement(递推 && 状压)
Description The 11th Zhejiang Provincial Collegiate Programming Contest is coming! As a problem sett ...
- BestCoder Round #93 比赛记录
机房又迎来了一次BC.大家都沸腾了... BC开场,大家全都瞬间开始 啪啦啪啦啪啦啪啦 都要赶紧水过第一题. 第一题明显直接贪心就好了,用map去重. 本人荣幸地第一个写完,提交 Wa. (崩溃的内心 ...
- 命令行启动nodejs方式 小总结
之前启动nodejs都是写一个命令行文件,如nodejs.cmd,内容为:start node E:\node\app.js. 今天突然想到之前也用过另外一种方式启动,就是在命令行通过cd命令先找到n ...