关于持久连接和 FastCGI

PHP 作为一种脚本解释语言,其解析器在执行完脚本后会释放所有资源,包括数据库连接等等。这样下次需要再执行脚本时,就需要重新连接数据库了。
频繁地创建和关闭连接,无疑会造成不必要的开销。因此,在 PHP 中引入了持久连接的概念。具体可以看:
http://php.net/manual/en/features.persistent-connections.php

持久连接,不能工作在 CGI 模式下,因为 CGI 进程结束后,会释放所有资源。
PHP 当前主流的运行模式有两种,一种是以 web server 的 module 运行,另一种是 fastcgi。
在这两种模式下,都能够使用持久连接,因为创建连接后连接资源可以交给 web server 或 fastcgi server。

我个人更偏向于用 fastcgi,结构清晰,并且能提升 web server 的处理性能。
来看看一段简短地描述:

After all, Apache already has mod_php.
However, there are advantages to running PHP with FastCGI. Separating the PHP code from the web server removes ‘bloat’ from the main server, and should improve the performance of non-PHP requests. Secondly, having one permanent PHP process as opposed to one per apache process means that shared resources like persistent database connections are used more efficiently.

在 fastcgi 模式下,一个 PHP 进程固定地占用一个持久连接,只有可能连接数据库的 PHP 脚本才有可能装入这个 PHP 进程。
而 module 模式下,每个 apache 进程都会加载 PHP 模块,每个 apache 进程都会占用一个持久连接,这样不管是不是在处理 PHP ,都要占用连接。
因此,fastcgi 比 module 能够更好地利用持久连接。

在使用持久连接时,需要特别注意的是,数据库设置的允许的最大连接数不能小于 PHP 可能的实例数。

  • 在 module 模式下,数据库连接数要大于 apache 可能的最大进程数。
  • 在 fastcgi 模式下,数据库连接数要大于 php-cgi 最大进程数。

否则,可能出现连接数不够无法连接到数据库的错误。

来做个应用题:
一个网站的 PHP 运行在 fastcgi 模式下,流量大概是 1亿/日,需要持久连接的资源有 3 种。请估算下要几个 php-cgi 实例,几个持久连接?

1亿/日,估算高峰期每秒请求数为日均压力的 10 倍,为 (1亿/86400)*10 = 11574 requests/second。
假设每个请求平均耗时 0.3 秒,那么至少需要运行 11574/3 = 3858 个 php-cgi 实例。
采用持久连接,每个资源需要 1 个连接,需要 3858*3 = 11574 个持久连接。

挺险的,如果用 tcp 连接,数量级再大一倍,连接数都不够用了(当然我们还可以用 Unix Domain Socket),不过这种量也不可能跑在单台服务器上,所以连接数的问题也不愁啦。

— EOF —

Gentoo 下搭建 Nginx+ MySQL + PHP (fastcgi) 环境

安装 Nginx

* 一条命令搞定:

USE=fastcgi emerge nginx

* 新建用户和组:

groupadd www

useradd www -g www

Nginx 安装好后默认会添加 nginx 组和 nginx 用户,不过我本身还是习惯新建个 www 组和 www 用户来做 HTTP 服务用户。若今后 HTTP 服务器更换为 apache 或是 lighttpd 时,用户名和用户组可以不变。

安装 MySQL

在装 PHP 前必须先装 MySQL,因为 PHP 里的 MySQL 操作函数需要 MySQL 头文件和库的支持。

emerge dev-db/mysql

* 初始化数据库:

我不习惯把数据库安装在默认路径 /var/lib/mysql 中,我把它放在 /work/db/3306/data 中。

mkdir -p /work/db/3306/data

mysql_install_db –basedir=/usr –datadir=/work/db/3306/data –user=mysql

* 修改配置文件:

vim /etc/mysql/my.cnf

将 datadir 修改为:

datadir = /work/db/3306/data

* 启动 MySQL:

/etc/init.d/mysql start

* 修改 root 密码:

mysqladmin -uroot password hily

* 测试数据库:

mysql -uroot -p

显示:

gentoo setup # mysql -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.0.84-log Gentoo Linux mysql-5.0.84-r1

Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.

mysql>

测试成功!

安装 PHP

以 fastcgi 方式来运行 PHP,需要安装 PHP-FPM

目前最后一个需要以 patch 形式安装 PHP-FPM 的 PHP 版本是 5.3.0,PHP 5.3.2 版本中将可能直接集成 PHP-FPM。

这里我就使用 PHP 5.3.0 来安装。

因为 Gentoo 中目录还没有集成 PHP-FPM 的 Portage,所以下面直接通过源码编译形式进行安装。

* 下载 PHP 5.3.0:

wget http://cn.php.net/distributions/php-5.3.0.tar.bz2

* 下载 PHP-FPM 补丁:

wget http://php-fpm.org/downloads/php-5.3.0-fpm-0.5.12.diff.gz

* 解压 PHP 并打 FPM 补丁:

tar jxf php-5.3.0.tar.bz2

gzip -cd php-5.3.0-fpm-0.5.12.diff.gz | patch -d php-5.3.0 -p1

* 安装 PHP 需要的库(根据自身需要):

emerge libpng

emerge jpeg

emerge freetype

USE=”png jpeg truetype” emerge gd

或者直接:

USE=”png jpeg truetype” emerge gd

* 配置并编译 PHP(根据自身需要):

cd php-5.3.0

./configure –prefix=/usr/local/php –with-config-file-path=/usr/local/php/etc –with-mysql=/usr –with-mysqli=/usr/bin/mysql_config –enable-fpm –enable-sockets –enable-pdo –with-pdo-mysql=/usr –with-gd –with-jpeg-dir –with-png-dir –with-freetype-dir –with-zlib

make && make install

* PHP 配置文件:

cp php.ini-production /usr/local/php/etc/php.ini

* PHP-FPM 配置文件:

vim /usr/local/php/etc/php-fpm.conf

修改 listen_address 为 socket 地址(socket 比 IP:Port 高效):

<value name=”listen_address”>/tmp/php-fpm.sock</value>

修改用户组和用户名:

Unix user of processes
<value name=”user”>www</value>

Unix group of processes
<value name=”group”>www</value>

修改 PHP-FPM 运行模式为 Apache-Like 模式:

<value name=”style”>apache-like</value>
<value name=”StartServers”>1</value>
<value name=”MinSpareServers”>1</value>
<value name=”MaxSpareServers”>5</value>

StartServers、MinSpareServers 和 MaxSpareServers 根据实际需要设置,我这里是虚拟机,没必要太大。

* PHP-FPM 启动脚本:

cp /usr/local/php/sbin/php-fpm /etc/init.d/php-fpm

* 启动 PHP-FPM

/etc/init.d/php-fpm start

添加启动服务

rc-update add nginx default

rc-update add mysql default

rc-update add php-fpm default

测试 Nginx+PHP

* 添加测试站点目录:

mkdir -p /work/www/test

echo “<?php phpinfo(); ?>” > /work/www/test/index.php

* 添加测试站点的 Nginx 配置:

vim /etc/nginx/nginx.conf

注释掉 server 段,在 http 段尾部加上:

include sites/*.enable;

之后每个站点的配置文件都以一个独立的文件保存在 /etc/nginx/sites 目录下,方便管理和维护。

mkdir /etc/nginx/sites

vim /etc/nginx/test.enable

test.enable 配置如下:

server {
listen       80;
server_name  test.local;

access_log  /work/www/logs/test.access.log  main;
error_log  /work/www/logs/test.error.log;

location / {
root   /work/www/test;
index  index.html index.htm index.php;
}

location ~ \.php$ {
root           /work/www/test;
fastcgi_index  index.php;
fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
include        fastcgi_params;
fastcgi_pass   unix:/tmp/php-fpm.sock;
}
}

* 新建存储日志目录:

mkdir /work/www/logs

* 本地 hosts 中添加记录:

192.168.1.10    test.local

192.168.1.10 是我这台 Gentoo 机器的 IP。

* 重新加载 Nginx 配置

/etc/init.d/nginx reload

* 访问:

http://test.local/

显示正常的 phpinfo 信息,则安装完成!

— EOF —

Nginx + MySQL + FastCGI + PHP + eAccelerator 简易安装配置手册

(本文所介绍的安装方法在 Debian 下进行,主要介绍用编译方式进行安装的方法,使用 package 安装较为简单,本文不做介绍。)

第一部分 安装指南

基本步骤:

a. 解压源码包:

tar zxf foobar.tar.gz

b. 运行配置脚本:

cd foobar/

./configure –option=xxx ….

c. 编译源码:

make

d. 安装:

make install

具体编译安装步骤请参考以下安装脚本(点此下载):

# install script for mysql, php, nginx
# writed by hilyjiang 20080718

# mysql
apt-get install -y libncurses5-dev
tar zxf mysql-5.0.51b.tar.gz
cd mysql-5.0.51b/
./configure –prefix=/usr/local/mysql –without-debug –with-client-ldflags=-all-static –with-mysqld-ldflags=-all-static –enable-assembler –with-extra-charsets=gbk,gb2312,utf8 –with-pthread –enable-thread-safe-client
make
make install
cp support-files/my-medium.cnf /usr/local/mysql/my.cnf
cd ../

# php lib
cd php
tar zxvf libiconv-1.12.tar.gz
cd libiconv-1.12/
./configure –prefix=/usr/local
make
make install
cd ../

tar zxvf freetype-2.3.7.tar.gz
cd freetype-2.3.7/
./configure
make
make install
cd ../

tar zxvf libpng-1.2.29.tar.gz
cd libpng-1.2.29/
./configure
make
make install
cd ../

tar zxvf jpegsrc.v6b.tar.gz
cd jpeg-6b/
./configure –enable-static –enable-shared
make
make install
make install-lib
cd ../

tar zxvf libxml2-2.6.32.tar.gz
cd libxml2-2.6.32/
./configure
make
make install
cd ../

tar zxvf libmcrypt-2.5.8.tar.gz
cd libmcrypt-2.5.8/
./configure
make
make install
/sbin/ldconfig
cd libltdl/
./configure –enable-ltdl-install
make
make install
cd ../../

tar zxvf mhash-0.9.9.tar.gz
cd mhash-0.9.9/
./configure
make
make install
cd ../

cp /usr/local/lib/libmcrypt.* /usr/lib
ln -s /usr/local/lib/libmhash.so.2 /usr/lib/libmhash.so.2

tar zxvf mcrypt-2.6.6.tar.gz
cd mcrypt-2.6.6/
./configure
make
make install
cd ../

tar zxf gd-2.0.35.tar.gz
cd gd-2.0.35/
./configure
make
make install
cd ../

tar zxf libssh2-0.12.tar.gz
cd libssh2-0.12/
./configure
make
make install
cd ../

# php
apt-get install -y libcurl3-dev
apt-get install -y bzip2
tar jxf php-5.2.6.tar.bz2
gzip -cd php-5.2.6-fpm-0.5.8.diff.gz | patch -d php-5.2.6 -p1
cd php-5.2.6/
./configure –prefix=/usr/local/php –with-config-file-path=/usr/local/php/etc –with-mysql=/usr/local/mysql –with-mysqli=/usr/local/mysql/bin/mysql_config –with-iconv-dir=/usr/local –with-freetype-dir –with-jpeg-dir –with-png-dir –with-zlib –with-libxml-dir –enable-xml –disable-debug –disable-rpath –enable-discard-path –enable-safe-mode –enable-bcmath –enable-shmop –enable-sysvsem –enable-inline-optimization –with-curl –with-curlwrappers –enable-mbregex –enable-fastcgi –enable-fpm –enable-force-cgi-redirect –enable-mbstring –with-mcrypt –with-gd –enable-gd-native-ttf –with-openssl –enable-ftp
make
make install
mkdir /usr/local/php/etc
cp php.ini-recommended /usr/local/php/etc/php.ini
cd ../

# php extensions
# memcache
apt-get -y install autoconf
tar zxf memcache-2.2.3.tgz
cd memcache-2.2.3/
/usr/local/php/bin/phpize
./configure –with-php-config=/usr/local/php/bin/php-config
make
make install
cd ../

# ssh2
tar zxf ssh2-0.10.tgz
cd ssh2-0.10/
/usr/local/php/bin/phpize
./configure –with-php-config=/usr/local/php/bin/php-config
make
make install
cd ../

# eaccelerator
tar jxf eaccelerator-0.9.5.3.tar.bz2
cd eaccelerator-0.9.5.3/
/usr/local/php/bin/phpize
./configure –with-php-config=/usr/local/php/bin/php-config
make
make install
cd ../
cd ../

# nginx
cd nginx
dpkg -i libgoogle-perftools0_0.98-1_i386.deb
dpkg -i libgoogle-perftools-dev_0.98-1_i386.deb

tar zxf pcre-7.7.tar.gz
cd pcre-7.7
./configure
make
make install
cd ../

tar zxf nginx-0.6.32.tar.gz
cd nginx-0.6.32/
./configure –prefix=/usr/local/nginx –with-http_stub_status_module –with-google_perftools_module
make
make install
mkdir /usr/local/nginx/logs/logbydate/
cd ../
cd ../

维护要点:

a. 编译软件或库时,最好在 configure 时配置使用默认的安装路径如 –prefix=/usr/local,以避免和使用包安装的软件冲突。也可以专门建立一个独立的目录,如 /usr/local/mysql 或 /home/apache。

b. 对冗繁的安装操作,最好写个安装脚本以便日后在多个服务器上自动部署。

第二部分 配置和维护

主要配置文件打包于此:etc.zip

1. Nginx

·主要配置文件路径:

/usr/local/nginx/conf/nginx.conf

/usr/local/nginx/conf/fastcgi_params

/usr/local/nginx/conf/sites/*

·启动 nginx:

/usr/local/nginx/sbin/nginx

·停止 nginx:

kill -TERM `cat /usr/local/nginx/logs/nginx.pid`

·测试配置:

/usr/local/nginx/sbin/nginx –t

·重新加载配置:

kill –HUP `cat /usr/local/nginx/logs/nginx.pid`

·增加新站点:

在 conf/sites/ 下为新站点建立一个配置文件,命名规则为 sitename.enable。

(在 nginx.conf中设置只有以.enable结尾的配置文件才会被加载)

测试配置:

/usr/local/nginx/sbin/nginx –t

重新加载配置:

kill –HUP `cat /usr/local/nginx/logs/nginx.pid`

·按日切分日志:

使用以下脚本按日切分Nginx的日志:

#! /bin/sh

log_dir="/usr/local/nginx/logs"

date_postfix=`date +%Y%m%d`

src_log=${log_dir}/test.access.log

tmp_log=${log_dir}/test.access.log.tmp

des_log=${log_dir}/logbydate/test.access.${date_postfix}.log

if [ ! -f ${des_log} ]; then

mv ${src_log} ${des_log}

else

mv ${src_log} ${tmp_log}

cat ${tmp_log} >> ${des_log}

rm ${tmp_log}

fi

kill -USR1 `cat /usr/local/nginx/logs/nginx.pid`

cron中设置每天 23:59 分执行该脚本:

$ crontab -uroot -e

# m h dom mon dow command

59 23 * * * /usr/local/nginx/logs/cronlog.sh

2. MySQL

·新建数据库服务器:

建立数据存放目录:

mkdir /home/db/testdb

chown mysql /home/db/testdb

安装 mysql 数据目录:

/usr/local/mysql/bin/mysql_install_db –basedir=/usr/local/mysql –datadir=/home/db/testdb/data –user=mysql

·拷贝并修改配置:

cp /usr/local/mysql/my.cnf /home/db/testdb/

/home/db/testdb/my.cnf:

[client]

port = 3306

socket = /home/db/testdb/mysql.sock

[mysqld]

port = 3306

socket = /home/db/testdb/mysql.sock

datadir = /home/db/testdb/data

pid-file = /home/db/testdb/mysql.pid

·建立启动和停止脚本:

/home/db/testdb/start.sh:

#! /bin/sh

/usr/local/mysql/bin/mysqld_safe –defaults-file=/home/db/testdb/my.cnf &

/home/db/testdb/stop.sh:

#! /bin/sh

/usr/local/mysql/bin/mysqladmin –defaults-file=/home/db/testdb/my.cnf -uroot -p shutdown

添加执行权限:

chmod +x /home/db/testdb/start.sh /home/db/testdb/stop.sh

·启动服务:

/home/db/testdb/start.sh

·停止服务:

/home/db/testdb/stop.sh

3. FastCGI-PHP(PHP-FPM

·主要配置文件路径:

/usr/local/php/etc/php.ini

/usr/local/php/etc/php-fpm.ini

·查看已加载PHP模块:

/usr/local/php/bin/php-cgi –m

·增加新的PHP模块:

编译安装:

tar zxf php-ext.tar.gz

cd php-ext/

/usr/local/php/bin/phpize

./configure –with-php-config=/usr/local/php/bin/php-config

make

make install

修改 /usr/local/php/etc/php.ini 的配置,在尾部加上 extension="php-ext.so"。

·启动FastCGI:

/usr/local/php/sbin/php-fpm start

·停止FastCGI:

/usr/local/php/sbin/php-fpm stop

·重启FastCGI:

/usr/local/php/sbin/php-fpm restart

·重新加载 FPM 配置:

/usr/local/php/sbin/php-fpm reload

4. 修改启动脚本

使用Tarball安装的程序,如果需要在系统启动时自动启动,需要在系统的启动脚本 /etc/rc.local 中增加相应项,如:

mkdir /tmp/eaccelerator/

chmod 777 /tmp/eaccelerator/

/home/db/testdb/start.sh

/usr/local/php/sbin/php-fpm start

/usr/local/nginx/sbin/nginx

— EOF —