CGI,FastCGI,PHP-CGI与PHP-FPM

本文转载自:https://segmentfault.com/q/1010000000256516

刚开始对这个问题我也挺纠结的,看了《HTTP权威指南》后,感觉清晰了不少。

首先,CGI是干嘛的?CGI是为了保证web server传递过来的数据是标准格式的,方便CGI程序的编写者。

web server(比如说nginx)只是内容的分发者。比如,如果请求/index.html,那么web server会去文件系统中找到这个文件,发送给浏览器,这里分发的是静态数据。好了,如果现在请求的是/index.php,根据配置文件,nginx知道这个不是静态文件,需要去找PHP解析器来处理,那么他会把这个请求简单处理后交给PHP解析器。Nginx会传哪些数据给PHP解析器呢?url要有吧,查询字符串也得有吧,POST数据也要有,HTTP header不能少吧,好的,CGI就是规定要传哪些数据、以什么样的格式传递给后方处理这个请求的协议。仔细想想,你在PHP代码中使用的用户从哪里来的。

当web server收到/index.php这个请求后,会启动对应的CGI程序,这里就是PHP的解析器。接下来PHP解析器会解析php.ini文件,初始化执行环境,然后处理请求,再以规定CGI规定的格式返回处理后的结果,退出进程。web server再把结果返回给浏览器。

好了,CGI是个协议,跟进程什么的没关系。那fastcgi又是什么呢?Fastcgi是用来提高CGI程序性能的。

提高性能,那么CGI程序的性能问题在哪呢?”PHP解析器会解析php.ini文件,初始化执行环境”,就是这里了。标准的CGI对每个请求都会执行这些步骤(不闲累啊!启动进程很累的说!),所以处理每个时间的时间会比较长。这明显不合理嘛!那么Fastcgi是怎么做的呢?首先,Fastcgi会先启一个master,解析配置文件,初始化执行环境,然后再启动多个worker。当请求过来时,master会传递给一个worker,然后立即可以接受下一个请求。这样就避免了重复的劳动,效率自然是高。而且当worker不够用时,master可以根据配置预先启动几个worker等着;当然空闲worker太多时,也会停掉一些,这样就提高了性能,也节约了资源。这就是fastcgi的对进程的管理。

那PHP-FPM又是什么呢?是一个实现了Fastcgi的程序,被PHP官方收了。

大家都知道,PHP的解释器是php-cgi。php-cgi只是个CGI程序,他自己本身只能解析请求,返回结果,不会进程管理(皇上,臣妾真的做不到啊!)所以就出现了一些能够调度php-cgi进程的程序,比如说由lighthttpd分离出来的spawn-fcgi。好了PHP-FPM也是这么个东东,在长时间的发展后,逐渐得到了大家的认可(要知道,前几年大家可是抱怨PHP-FPM稳定性太差的),也越来越流行。

好了,最后来回来你的问题。
网上有的说,fastcgi是一个协议,php-fpm实现了这个协议

对。

有的说,php-fpm是fastcgi进程的管理器,用来管理fastcgi进程的

对。php-fpm的管理对象是php-cgi。但不能说php-fpm是fastcgi进程的管理器,因为前面说了fastcgi是个协议,似乎没有这么个进程存在,就算存在php-fpm也管理不了他(至少目前是)。 有的说,php-fpm是php内核的一个补丁

以前是对的。因为最开始的时候php-fpm没有包含在PHP内核里面,要使用这个功能,需要找到与源码版本相同的php-fpm对内核打补丁,然后再编译。后来PHP内核集成了PHP-FPM之后就方便多了,使用--enalbe-fpm这个编译参数即可。

有的说,修改了php.ini配置文件后,没办法平滑重启,所以就诞生了php-fpm

是的,修改php.ini之后,php-cgi进程的确是没办法平滑重启的。php-fpm对此的处理机制是新的worker用新的配置,已经存在的worker处理完手上的活就可以歇着了,通过这种机制来平滑过度。

还有的说PHP-CGI是PHP自带的FastCGI管理器,那这样的话干吗又弄个php-fpm出

不对。php-cgi只是解释PHP脚本的程序而已。

CentOS搭建局域网yum服务器

  • 本文引用自http://my.oschina.net/hanjiafu/blog/145140

 

搭建局域网的yum服务器需要做两个准备工作,以四台服务器为例,ip地址为:192.168.1.101,192.168.1.102,192.168.1.103,192.168.1.104.其中192.168.1.101作为yum服务器,其它三台服务器通过101来安装rpm包。

首先将光盘挂载到101上面,然后将光盘中的Packages(RPM包)和repodata(rpm包的一些序列文件)拷贝到101的localrpm文件间下边。

#cd localrpm

# python -m SimpleHTTPServer 8000

通过这两个命令就将这些101作为了包服务器,101成为yum源。

在需要yum服务的服务器上比如102,

# cd /etc/yum.repos.d

将该目录下的所有文件备份,然后创建local.repo文件中的内容为

[local]
name=Server
baseurl=http://192.168.1.101:8000#提供yum源服务的地址
enable=1
gpgcheck=0
然后执行

# yum clean all
# yum list    如何出现里面的包名称即安装成功了;

#yum install screen 通过安装screen来验证是否安装成功。

inotify+unison双向同步环境部署

  • 步骤一,设置分别在两台服务器进行如下设置

 mkdir ~/.ssh
 chmod 700 ~/.ssh
 生成RSA密钥
 ssh-keygen -t rsa
  • 步骤二,发送自己的密钥(/root/.ssh/id_rsa.pub)到另一台服务器

scp id_rsa.pub root@172.16.0.37:/home/root/.ssh/172.16.0.38    (172.16.0.38发送自己的密钥到172.16.0.37上的/home/root/.ssh/172.16.0.38文件)
scp id_rsa.pub root@172.16.0.38:/home/root/.ssh/172.16.0.37    (172.16.0.37发送自己的密钥到172.16.0.38上的/home/root/.ssh/172.16.0.37文件)
cd /root/.ssh
cat 172.16.0.38 >> authorized_keys  (172.16.0.37将172.16.0.38的密钥文件保存到authorized_keys )
cat 172.16.0.37 >> authorized_keys    (172.16.0.38将172.16.0.37的密钥文件保存到authorized_keys )

如果出现Agent admitted failure to sign using the key,试试ssh-add命令。

这时候,两台服务器应该可以不用命令互相访问了。

ssh 172.16.0.37 date 看看是否不需要输入密码

ssh 172.16.0.38 date 看看是否不需要输入密码

  • 步骤三,安装、配置inotify+unison
安装unison
 首先安装ocaml,版本至少为3.07或更高
 下载地址:http://caml.inria.fr/pub/distrib/ocaml-3.10/
 tar xf ocaml-3.10.2.tar.gz
 cd ocaml-3.10.2
 ./configure
 make world opt
 make install
 cd ..

 安装unison
下载地址:http://www.seas.upenn.edu/~bcpierce/unison//download/releases/unison-2.13.16/
 tar xvf unison-2.13.16.tar.gz
 cd unison-2.13.16
 make UISTYLE=text THREADS=true STATIC=true
 cp unison /usr/local/bin
 cd ..

 安装inotify
下载地址:http://inotify-tools.sourceforge.net
 tar xvf inotify-tools-3.14.tar.gz
 cd inotify-tools-3.14
 ./configure
 make
 make install
 cd ..

提供一下脚本:

#/bin/bash
 local_src1="/home/server1/"
 local_src2="/home/server1_2/"
/usr/local/bin/inotifywait -mrq -e create,delete,modify,move $local_src1 $local_src2 | while read line; do
 /usr/local/bin/unison -batch ${line%% *} ssh://172.16.0.38/${line%% *}
done

如果有多个目录,可以同理添加。

问题来了,当我把这个文件加入到/etc/rc.d/rc.local的时候,unison 一直都未能执行,也不知道为什么…

于是我改用了crontab…脚本响应做修改,避免inotifywait程序重复运行..

#/bin/bash
 local_src1="/home/server1/"
 local_src2="/home/server1_2/"
 RESULT=`ps -e|grep 'inotifywait'|sed -e "/grep/d"`
 if [ -z "$RESULT" ];then
/usr/local/bin/inotifywait -mrq -e create,delete,modify,move $local_src1 $local_src2 | while read line; do
 echo $line >> /home/inotify.log
 echo -batch ${line%% *} ssh://172.16.0.38/${line%% *} >> /home/inotify.log
 /usr/local/bin/unison -batch ${line%% *} ssh://172.16.0.38/${line%% *} >> /home/inotify.log
 done
fi

cron:

*/5 * * * * nohup /bin/bash /root/inotify.sh >/dev/null 2>&1

免费ARP

免费ARP的作用:

向局域网内机器广播自己的ip-mac对应情况,让其他设备及时更新arp表(特别是网关)。

若更新不及时,其他设备可能会使用其本身的arp表发送数据包,这将使得数据包无法正常送达。

 

在我们的工作环境中最常见的应用可能是设备双机热备的应用场景,在双机热备的工作模式下,由主设备切换到备用设备时,与之相连的设备的ARP表项需要由以前主设备的MAC地址更新为现在主设备(切换前的从设备)的MAC地址,这时,一般从设备在切换为主设备时,就利用向网络中发送免费ARP请求报文, 达到让其他设备更新ARP表项的效果。

 

实验发现,Centos6只会在开机的时候广播免费arp包,而在ip addr add命令后不会发送免费arp广播,这会使得局域网内的设备中arp表无法及时更新,使得外网可能在arp老化周期内无法访问到现在的主设备。

 

添加ip后,运行Arping命令可以解决这个问题。

在linux下发送arping -A -c 10 -I eth0 172.16.0.30
(-c 10 为设置只发送10次广播,根据需要调整。)
可以主动发送免费arp包,更新同网段其他设备的arp表

arping

一下为局域网内其他主机的arp -a命令分别在三种情况后的结果:
1、一开始, 172.16.0.30绑定在 172.16.0.37
2、后来, 172.16.0.30解绑 172.16.0.37,绑定在 172.16.0.38 后
3、 172.16.0.38上运行arping -A -w 10 -I eth0 172.16.0.30 后win

抓包结果:

1、windows发送的免费arp包


windows的arp包(用于ip冲突检测?)

2、centos6开机时发送的免费arp包

Linux开机发送的arp包

3、在linux下arping -A -I eth0 172.16.0.30 发送的arp包

arping -D 172.16.0.30