nginx

关注公众号 jb51net

关闭
首页 > 网站技巧 > 服务器 > nginx > Nginx FastCGI  PHP 动态页面

Nginx FastCGI 实现 PHP 动态页面解析的原理与配置

作者:时间售卖铺

本文详解Nginx通过FastCGI协议与PHP-FPM协同实现PHP动态页面解析的原理与配置,涵盖CGI/FastCGI演进、PHP-FPM进程模型、Nginx fastcgi_pass核心指令,感兴趣的朋友跟随小编一起看看吧

前面章节学习的 Nginx 七层、四层负载均衡都偏向静态资源与 TCP/UDP 流量转发。Nginx 本身只能处理静态 HTML、图片等静态资源,不能直接解析 PHP 这类动态脚本。FastCGI 就是 Nginx 和 PHP 解析器之间通信的标准协议,用来实现动态网页解析。

1.1 CGI、FastCGI、PHP-FPM 基础概念

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 文件,初始化环境,请求结束的时候再关闭进程。每一个请求都要重复创建、初始化、销毁进程,资源开销巨大。 FastCGI 是 CGI 的优化版本:进程处理完请求之后不会直接关闭,进程保持常驻,可以持续处理多个请求,省去反复创建销毁进程、重复初始化环境的开销,大幅提升动态脚本处理性能。

什么是 PHP-FPM?

PHP-FPM(FastCGI Process Manager:FastCGI 进程管理器),是一个实现了 FastCGI 协议的程序,并且自带完善的进程管理功能。

Nginx 模块依赖:ngx_http_fastcgi_module,默认编译 Nginx 时一般自带,专门用来转发 fastcgi 请求。

1.2 FastCGI 核心配置指令

fastcgi_pass address:port;
#转发请求到后端fastcgi服务地址,支持location、if in location
fastcgi_index name;
#fastcgi默认首页,常用 fastcgi_index index.php;
fastcgi_param parameter value [if_not_empty];
#传递环境变量、Nginx内置变量给PHP-FPM
fastcgi_param REMOTE_ADDR $remote_addr;     #客户端源IP
fastcgi_param REMOTE_PORT $remote_port;     #客户端端口
fastcgi_param SERVER_ADDR $server_addr;     #Nginx服务IP
fastcgi_param SERVER_PORT $server_port;     #Nginx服务端口
fastcgi_param SERVER_NAME $server_name;     #虚拟主机server_name

基础模板示例:

location ~ \.php$ {
    root /scripts;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}

include fastcgi_params; 文件由 Nginx 自带,里面预先定义了大量 FastCGI 需要传递的参数,简化配置。

1.3 实战案例:Nginx + PHP-FPM(同机部署)

推荐源码编译 PHP,可以自由开启扩展、自定义安装路径。PHP 官网:www.php.net

1.3.1 PHP 8.3.30 源码编译部署

1、下载源码包与依赖包

[root@Nginx ~]# wget https://www.php.net/distributions/php-8.3.30.tar.gz
[root@Nginx ~]# wget https://mirrors.aliyun.com/rockylinux/9.7/devel/x86_64/os/Packages/o/oniguruma-devel-6.9.6-1.el9.6.x86_64.rpm

2、解压源码包

[root@Nginx ~]# tar zxf php-8.3.30.tar.gz
[root@Nginx ~]# ls
anaconda-ks.cfg                lee.png            nginx-1.29.4.tar.gz  test.c
daolian.png                    nginx-1.28.1       php-8.3.30
echo-nginx-module-0.64         nginx-1.28.1.tar.gz php-8.3.30.tar.gz
echo-nginx-module-0.64.tar.gz  nginx-1.29.4       test
[root@Nginx ~]# cd php-8.3.30

3、安装编译依赖

[root@Nginx ~]# dnf install gcc -y
[root@Nginx ~]# dnf install systemd-devel.x86_64 -y
[root@Nginx ~]# dnf install libxml2-devel.x86_64 -y
[root@Nginx ~]# dnf install sqlite-devel.x86_64 -y
[root@Nginx ~]# dnf install libcurl-devel.x86_64 -y
[root@Nginx ~]# dnf install libpng-devel.x86_64 -y
[root@Nginx ~]# dnf search oniguruma -y
#安装oniguruma-devel依赖,依赖缺失使用--nodeps强制安装
[root@Nginx ~]# rpm -ivh oniguruma-devel-6.9.6-1.el9.6.x86_64.rpm --nodeps

4、configure 编译配置

[root@Nginx ~]# cd php-8.3.30/
[root@Nginx php-8.3.30]# ./configure \
--prefix=/usr/local/php \
--with-config-file-path=/usr/local/php/etc \
--enable-fpm  \
--with-fpm-user=nginx \
--with-fpm-group=nginx \
--with-curl \
--with-iconv \
--with-mhash \
--with-zlib \
--with-openssl \
--enable-mysqlnd \
--with-mysqli \
--with-pdo-mysql \
--disable-debug \
--enable-sockets \
--enable-soap \
--enable-xml \
--enable-ftp \
--enable-gd \
--enable-exif \
--enable-mbstring \
--enable-bcmath \
--with-fpm-systemd

编译 & 安装

[root@Nginx php-8.3.30]# make && make install

5、PHP-FPM 配置文件初始化

[root@Nginx php-8.3.30]# cd /usr/local/php/etc
[root@Nginx etc]# cp -p php-fpm.conf.default  php-fpm.conf
[root@Nginx etc]# vim php-fpm.conf

修改 pid 配置:

[global]
pid = run/php-fpm.pid

进入 pool 配置目录:

[root@Nginx etc]# cd php-fpm.d/
[root@Nginx php-fpm.d]# cp www.conf.default www.conf
[root@Nginx php-fpm.d]# vim www.conf
#修改监听地址
listen = 0.0.0.0:9000

拷贝生产版 php.ini,修改时区:

[root@Nginx php-fpm.d]# cp /root/php-8.3.30/php.ini-production  /usr/local/php/etc/php.ini
[root@Nginx php-fpm.d]# vim /usr/local/php/etc/php.ini
date.timezone = Asia/Shanghai

6、配置 systemd 管理 php-fpm

[root@Nginx ~]# cp /root/php-8.3.30/sapi/fpm/php-fpm.service /lib/systemd/system/
[root@Nginx ~]# vim /lib/systemd/system/php-fpm.service
#注释掉ProtectSystem=full
#ProtectSystem=full

重载 unit、开机自启并启动服务

[root@Nginx ~]# systemctl daemon-reload
[root@Nginx ~]# systemctl enable --now php-fpm
#查看监听端口
[root@Nginx ~]# netstat -antlupe | grep php
tcp        0      0 0.0.0.0:9000            0.0.0.0:*               LISTEN      0          329917     165562/php-fpm: mas

7、配置系统环境变量

[root@Nginx ~]# vim ~/.bash_profile
export PATH=$PATH:/usr/local/nginx/sbin:/usr/local/php/sbin:/usr/local/php/bin
[root@Nginx ~]# source  ~/.bash_profile
#验证
[root@Nginx ~]# php -m

1.3.2 Nginx 整合 PHP-FPM,访问测试

#创建网站目录
[root@Nginx ~]# mkdir /webdata/dragon.org/php/html -p
#新建phpinfo测试页
[root@Nginx ~]# vim /webdata/dragon.org/php/html/index.php

index.php 内容:

<?php
    phpinfo();
?>

编辑 Nginx 子配置文件:

[root@Nginx ~]# vim /usr/local/nginx/conf.d/php.conf
server {
    listen 80;
    server_name php.dragon.org;
    root /webdata/dragon.org/php/html;
    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        include fastcgi.conf;
    }
}

重载 Nginx 配置,浏览器访问 php.dragon.org/index.php 查看 php 信息页面。

1.4 PHP 动态扩展:Memcache 缓存模块

Memcached 不是数据库,是纯内存分布式 K-V 缓存系统。原理:内存换速度,LRU 淘汰策略,数据不保存在磁盘,适合缓存高频查询数据,减少数据库压力。 软件地址:http://pecl.php.net/package/memcache

1.4.1 部署 Memcached 服务

[root@Nginx ~]# dnf install memcached.x86_64 -y
[root@Nginx ~]# vim /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS="-l 0.0.0.0,::1"

启动服务

[root@Nginx ~]# systemctl enable --now memcached.service
[root@Nginx ~]# netstat -antlupe | grep memcache
tcp        0      0 0.0.0.0:11211           0.0.0.0:*               LISTEN      991        437305     166169/memcached
tcp6       0      0 ::1:11211               :::*                    LISTEN      991        437306     166169/memcached

1.4.2 编译 memcache PHP 扩展

[root@Nginx ~]# php -m
[root@Nginx ~]# tar zxf memcache-8.2.tgz
[root@Nginx ~]# cd memcache-8.2/
[root@Nginx memcache-8.2]# dnf install autoconf -y
[root@Nginx memcache-8.2]# phpize
[root@Nginx memcache-8.2]# ./configure  && make && make install
#查看编译生成的扩展文件
[root@Nginx memcache-8.2]# ls /usr/local/php/lib/php/extensions/no-debug-non-zts-20230831/
memcache.so  opcache.so

修改 php.ini 加载扩展

[root@Nginx memcache-8.2]# vim /usr/local/php/etc/php.ini
extension=memcache

重启 php-fpm 验证扩展

[root@Nginx memcache-8.2]# systemctl restart php-fpm.service
[root@Nginx memcache-8.2]# php -m  | grep memcache
memcache

1.4.3 AB 压测对比(PHP 层缓存)

准备 memcache 管理页面:

[root@Nginx memcache-8.2]# vim memcache.php
define('ADMIN_USERNAME','admin');
define('ADMIN_PASSWORD','123');
$MEMCACHE_SERVERS[] = '172.25.254.10:11211';

拷贝到网站目录:

[root@Nginx memcache-8.2]# cp -p memcache.php  /webdir/timinglee.org/php/html/
[root@Nginx memcache-8.2]# cp -p example.php /webdir/timinglee.org/php/html/
[root@Nginx memcache-8.2]# systemctl stop memcached.service
[root@Nginx memcache-8.2]# ab -n 1000 -c 300 php.dragon.org/index.php

压测结果摘要:大量请求失败,并发压力下性能较差

Complete requests:   1000
Failed requests:     994
Requests per second: 5000.98 [#/sec] (mean)
[root@Nginx memcache-8.2]# systemctl start memcached.service
[root@Nginx memcache-8.2]# ab -n 1000 -c 300 php.dragon.org/index.php

压测摘要:失败请求数量大幅下降,缓存生效

Complete requests:   1000
Failed requests:     105
Requests per second: 5174.32 [#/sec] (mean)

小结:这一层是PHP 代码层面调用 memcache 缓存,缓存逻辑写在 PHP 程序里。下面我们实现 Nginx 层直接缓存,由 Nginx 优先读取 memcache。

1.5 Nginx + Memcache 高速缓存(srcache+memc 模块)

原理:第三方模块 memc-nginx-module + srcache-nginx-module,让 Nginx 直接读写 memcache。请求到达 Nginx 优先去 memcache 读取缓存,命中直接返回;未命中才转发给 fastcgi 处理,处理完成后存入 memcache,这一层缓存是 Nginx 侧,性能更高。 原生 Nginx 不自带这两个模块,需要重新编译 Nginx 添加第三方模块。

1.5.1 重新编译 Nginx,添加 memc、srcache 模块

[root@Nginx ~]# systemctl stop nginx.service
#备份原有配置
[root@Nginx ~]# cp /usr/local/nginx/conf/   /mnt/ -r
[root@Nginx ~]# rm -fr /usr/local/nginx/
[root@Nginx ~]# rm -rf nginx-1.29.4 nginx-1.28.1
#解压源码和第三方模块包
[root@Nginx ~]# tar zxf nginx-1.28.1.tar.gz
[root@Nginx ~]# cd nginx-1.28.1/
[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.28.1/

编译参数

[root@Nginx nginx-1.28.1]# ./configure  --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_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-module-0.33
[root@Nginx nginx-1.28.1]# make && make install

恢复备份配置文件

[root@Nginx ~]# cd /usr/local/nginx/conf
[root@Nginx conf]# rm -fr nginx.conf
[root@Nginx conf]# cp /mnt/conf/nginx.conf /mnt/conf/conf.d/ . -r
[root@Nginx conf]# systemctl start nginx.service

1.5.2 Nginx 配置 srcache 缓存

[root@Nginx conf]# vim /usr/local/nginx/conf/conf.d/php.conf
upstream memcache {
    server 127.0.0.1:11211;
    keepalive 512;
}
server {
    listen 80;
    server_name php.timinglee.org;
    root /webdir/timinglee.org/php/html;
    index index.php index.html;
    location /memc {
        internal;
        memc_connect_timeout 100ms;
        memc_send_timeout 100ms;
        memc_read_timeout 100ms;
        set $memc_key $query_string;
        set $memc_exptime 300;
        memc_pass memcache;
    }
    location ~ \.php$ {
        set $key $uri$args;
        srcache_fetch GET /memc $key;
        srcache_store PUT /memc $key;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        include fastcgi.conf;
    }
}

重载 Nginx

[root@Nginx conf]# nginx  -s reload

1.5.3 压测验证 Nginx 层缓存效果

[root@Nginx conf]# ab -n 10000 -c500 http://php.dragon.org/index.php

压测结果摘要:缓存命中后无失败请求,QPS 大幅提升

Complete requests:  10000
Failed requests:     0
Requests per second: 26289.09 [#/sec] (mean)

到此这篇关于Nginx FastCGI 实现 PHP 动态页面解析的文章就介绍到这了,更多相关Nginx FastCGI PHP 动态页面内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文