FastCGI (FCGI) 是一种协议,用于改善 Web 服务器和应用程序之间的通信效率。它是在 CGI(Common Gateway Interface)的基础上发展起来的,旨在解决 CGI 在处理大量并发请求时存在的性能问题。
CGI的由来
最早的Web服务器只能简单地响应浏览器发来的HTTP请求,并将存储在服务器上的HTML文件返回给浏览器,也就是静态html文件,但是后期随着网站功能增多网站开发也越来越复杂,以至于出现动态技术,比如像php(1995年)、java(1995),python(1991)语言开发的网站,但是nginx/apache服务器并不能直接运行 php、java这样的文件,apache实现的方式是打补丁,但是nginx缺通过与第三方基于协议实现,即通过某种特定协议将客户端请求转发给第三方服务处理,第三方服务器会新建新的进程处理用户的请求,处理完成后返回数据给Nginx并回收进程,最后nginx在返回给客户端,那这个约定就是通用网关接口(common gateway interface,简称CGI),CGI(协议) 是web服务器和外部应用程序之间的接口标准,是cgi程序和web服务器之间传递信息的标准化接口。
为什么会有FastCGI
?
CGI协议虽然解决了语言解析器和 Web Server 之间通讯的问题,但是它的效率很低,因为 Web Server
每收到一个请求都会创建一个CGI进程,PHP解析器都会解析php.ini文件,初始化环境,请求结束的时候
再关闭进程,对于每一个创建的CGI进程都会执行这些操作,所以效率很低,而FastCGI是用来提高CGI性能的,FastCGI每次处理完请求之后不会关闭掉进程,而是保留这个进程,使这个进程可以处理多个请
求。这样的话每个请求都不用再重新创建一个进程了,大大提升了处理效率。
什么是PHP-FPM?
PHP-FPM(FastCGI Process Manager
:
- FastCGI进程管理器)是一个实现了Fastcgi的程序,并且提供进程管理的功能。
- 进程包括master进程和worker进程。master进程只有一个,负责监听端口,接受来自web server
的请求 - worker进程一般会有多个,每个进程中会嵌入一个PHP解析器,进行PHP代码的处理。
FastCGI 的特点
-
持久连接:FastCGI 允许一个持久的进程模型,在这个模型下,FastCGI 进程被启动后会一直运行,而不是为每个请求单独启动和终止,这样可以显著减少进程创建和销毁的开销。
-
多线程或多进程:FastCGI 支持多线程或多进程模型,这意味着单个 FastCGI 进程可以同时处理多个请求,提高了资源利用率。
-
异步处理:FastCGI 还支持异步 I/O 操作,这使得 FastCGI 应用程序能够更好地利用系统资源,并且在等待 I/O 完成时可以继续处理其他请求。
-
语言无关:FastCGI 可以用任何编程语言实现,只要该语言支持网络编程并能够处理 TCP/IP 或 Unix domain sockets。
-
平台无关:FastCGI 可以在多种操作系统上运行,包括 Linux、Windows 和 macOS。
FastCGI 的工作流程
- 初始化:Web 服务器启动时,它启动一个或多个 FastCGI 进程。
- 接收请求:当 Web 服务器收到 HTTP 请求时,它解析请求并将其转发给 FastCGI 进程。
- 处理请求:FastCGI 进程处理请求,并生成动态内容。
- 发送响应:FastCGI 进程将响应内容发送回 Web 服务器。
- 返回响应:Web 服务器将 FastCGI 进程的响应合并到 HTTP 响应中,并将其发送给客户端。
使用场景
FastCGI 主要用于以下场景:
- 高性能 Web 应用:需要处理大量并发请求的应用程序。
- 动态内容生成:如 PHP、Python、Ruby 等脚本语言编写的应用程序,这些语言通常用于生成动态网页内容。
- 资源密集型应用:对于那些需要大量计算资源的应用程序,FastCGI 能够更高效地管理这些资源。
实现方式
Nginx基于模块ngx_http_fastcgi_module
实现通过fastcgi
协议将指定的客户端请求转发至php-fpm
处
理,其配置指令如下:
示例
以 Nginx 作为 Web 服务器配置 FastCGI 的例子:
fastcgi_pass address:port;
#转发请求到后端服务器,address为后端的fastcgi server的地址,可用位置:location, if in
location
fastcgi_index name;
#fastcgi默认的主页资源,示例:fastcgi_index index.php;
fastcgi_param parameter value [if_not_empty];
#设置传递给FastCGI服务器的参数值,可以是文本,变量或组合,可用于将Nginx的内置变量赋值给自定义
key
fastcgi_param REMOTE_ADDR $remote_addr; #客户端源IP
fastcgi_param REMOTE_PORT $remote_port; #客户端源端口
fastcgi_param SERVER_ADDR $server_addr; #请求的服务器IP地址
fastcgi_param SERVER_PORT $server_port; #请求的服务器端口
fastcgi_param SERVER_NAME $server_name; #请求的server name
Nginx默认配置示例:
location ~ \.php$ {
root /scripts;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; #默认脚本路径
#fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params; #此文件默认系统已提供,存放的相对路径为
prefix/conf
}
在这个配置文件中,Nginx 将所有 .php
文件的请求转发给监听在 127.0.0.1:9000 的 FastCGI 服务器(通常是 PHP-FPM),然后 FastCGI 服务器处理 PHP 请求并将结果返回给 Nginx,最后由 Nginx 发送给客户端。
Nginx与php-fpm在同一服务器示例
配置php优化
[root@Nginx ~]# cd /usr/local/php/etc
[root@Nginx etc]# cp php-fpm.conf.default php-fpm.conf
[root@Nginx etc]# vim php-fpm.conf
去掉注释
pid = run/php-fpm.pid #指定pid文件存放位置
[root@Nginx etc]# cd php-fpm.d/
[root@Nginx php-fpm.d]# cp www.conf.default www.conf
#生成主配置文件
[root@Nginx php-fpm.d]# cd /root/php-8.3.9/
[root@Nginx php-8.3.9]# cp php.ini-production /usr/local/php/etc/php.ini
[root@Nginx ~]# vim /usr/local/php/etc/php.ini
[Date]
; Defines the default timezone used by the date functions
; https://php.net/date.timezone
date.timezone = Asia/Shanghai #修改时区
#生成启动文件
[root@Nginx ~]# cd /root/php-8.3.9/
[root@Nginx php-8.3.9]# cp sapi/fpm/php-fpm.service /lib/systemd/system/
# Mounts the /usr, /boot, and /etc directories read-only for processes invoked by
this unit.
#ProtectSystem=full #注释该内容
[root@Nginx php-8.3.9]# systemctl start php-fpm.service
[root@Nginx php-8.3.9]# netstat -antlupe | grep php
tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 0
820758 176202/php-fpm: mas
准备php测试页面
[root@Nginx ~]# mkdir /data/php -p
[root@centos8 ~]# cat /data/php/index.php #php测试页面
<?php
phpinfo();
?>
Nginx配置转发
Nginx安装完成之后默认生成了与fastcgi的相关配置文件,一般保存在nginx的安装路径的conf目录当
中,比如/apps/nginx/conf/fastcgi.conf、/apps/nginx/conf/fastcgi_params。
[root@Nginx ~]# vim /usr/nginx/conf.d/php.conf
server {
listen 80;
server_name php.exmple.org;
root /data/php;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}
#重启Nginx并访问web测试
[root@Nginx ~]# nginx -s reload
添加php环境变量
[root@Nginx ~]# vim .bash_profile
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/bin:/apps/nginx/sbin:/usr/local/php/bin
export PATH
[root@Nginx ~]# source .bash_profile
PHP的动态缓存模块
安装memcache模块
[root@Nginx ~]# tar zxf memcache-8.2.tgz
[root@Nginx ~]# cd memcache-8.2/
[root@Nginx memcache-8.2]# yum install autoconf
[root@Nginx memcache-8.2]# phpize
[root@Nginx memcache-8.2]# ./configure && make && make install
Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-nonzts-20230831/
[root@Nginx memcache-8.2]# ls /usr/local/php/lib/php/extensions/no-debug-non-zts20230831/
memcache.so opcache.so
复制测试文件到nginx发布目录
[root@Nginx ~]# cd memcache-8.2/
[root@Nginx memcache-8.2]# ls
autom4te.cache config.log configure.ac example.php Makefile.fragments
README
build config.m4 config.w32 include Makefile.objects runtests.php
config9.m4 config.nice CREDITS libtool memcache.la src
config.h config.status docker LICENSE memcache.php
tests
config.h.in configure Dockerfile Makefile modules
[root@Nginx memcache-8.2]# cp example.php memcache.php /data/php/
[root@Nginx ~]# vim /data/php/memcache.php
define('ADMIN_USERNAME','admin'); // Admin Username
define('ADMIN_PASSWORD','lee'); // Admin Password
define('DATE_FORMAT','Y/m/d H:i:s');
define('GRAPH_SIZE',200);
define('MAX_ITEM_DUMP',50);
$MEMCACHE_SERVERS[] = 'localhost:11211'; // add more as an array
#$MEMCACHE_SERVERS[] = 'mymemcache-server2:11211'; // add more as an array
配置php加载memcache模块
[root@Nginx ~]# yum install memcached -y
[root@Nginx ~]# systemctl enable --now memcached.service
[root@Nginx ~]# netstat -antlupe | grep memcache
tcp 0 0 127.0.0.1:11211 0.0.0.0:* LISTEN
976 1037243 186762/memcached
[root@Nginx ~]# cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS="-l 127.0.0.1,::1"
测试示例:
php高速缓存
在我们安装的nginx中默认不支持memc和srcache功能,需要借助第三方模块来让nginx支持此功能,所
以nginx需要重新编译
[root@Nginx ~]# rm -fr /usr/nginx
[root@Nginx ~]# tar zxf srcache-nginx-module-0.33.tar.gz
[root@Nginx ~]# tar zxf memc-nginx-module-0.20.tar.gz
[root@Nginx ~]# cd nginx-1.26.1/
[root@Nginx nginx-1.26.1]# ./configure --prefix=/apps/nginx --user=nginx --
group=nginx --with-http_ssl_module --with-http_v2_module --withhttp_realip_module --with-http_stub_status_module --with-http_gzip_static_module
--with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module --
add-module=/root/memc-nginx-module-0.20 --add-module=/root/srcache-nginx-module0.33
[root@Nginx nginx-1.26.1]# make && make install
[root@Nginx ~]# vim /apps/nginx/conf.d/php.conf
upstream memcache {
server 127.0.0.1:11211;
keepalive 512;
}
server {
listen 80;
server_name php.timinglee.org;
root /data/php;
location /memc {
internal;
memc_connect_timeout 100ms;
memc_send_timeout 100ms;
memc_read_timeout 100ms;
set $memc_key $query_string; #使用内置变量$query_string来作为key
set $memc_exptime 300; #缓存失效时间300秒
memc_pass memcache;
}
location ~ \.php$ {
set $key $uri$args; #设定key的值
srcache_fetch GET /memc $key; #检测mem中是否有要访问的php
srcache_store PUT /memc $key; #缓存为加载的php数据
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}
[root@Nginx ~]# systemctl start nginx.service