WEB服务与NGINX(21)- nginx 的fastcgi反向代理功能
1. NGINX实现fastcgi反向代理
1.1 fastcgi概述
-
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
PHP是通用服务器端脚本编程语言,其主要用于web开发以实现动态web页面,它也是最早实现将脚本嵌入HTML源码文档中的服务器端脚本语言之一。同时,php还提供了一个命令行接口,因此,其也可以在大多数系统上作为一个独立的shell来使用,意味着php可以在其交互式窗口直接运行。
官方网站
-
php-fpm
PHP-FPM(FastCGI Process Manager:FastCGI进程管理器)是一个实现了Fastcgi的程序,并且提供进程管理的功能。进程包括master进程和worker进程。master进程只有一个,负责监听端口,接受来自webserver的请求。worker进程一般会有多个,每个进程中会嵌入一个PHP解析器,进行PHP代码的处理。
php本身只是解释器,配合fpm,让php以守护进程的方式运行,监听在某个套接字上,接收前端的web服务器的请求。
php-fpm运行过程:
请求资源先发送给web服务器,web服务器通过fastcgi客户端模块去请求fastcgi的服务端,即fpm运行的php server,由php server处理用户请求,将响应的数据交由WEB服务器返回给客户端。
php-fpm通常监听在TCP/9000端口。
1.2 nginx实现fastcgi相关参数
以下指令由ngx_http_fastcgi_module模块提供。
-
fastcgi_pass address:port
设置FastCGI服务器的地址,域名或IP地址和端口
address:后端的fastcgi server的地址
支持环境:location, if in location
-
fastcgi_index name
fastcgi默认的主页资源,URI的资源路径
支持环境:http, server, location
示例
fastcgi_index index.php;
-
fastcgi_param parameter value [if_not_empty]
支持环境:http, server, location
设置传递给FastCGI服务器的参数值,可以是文本,变量或组合,将 Nginx 中的变量翻译成 PHP 中能够理解的变量。
nginx支持http协议,要将用户的请求发送给后端的FastCGI,后端FastCGI使用的协议与http不同,需要与其协商达到互相通讯的目的, 要传递给 FastCGI服务器的参数值,可以是文本,变量或组合,安装nginx后在有写好的参数文件(/etc/nginx/fastcgi_params.default ),直接调用即可。
[root@nginx01 ~]# cat /etc/nginx/fastcgi_params fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; # PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200;
以上变量中缺少了一个关键参数,即告知前端nginx,php程序所在的路径,使用以下变量进行赋值:
fastcgi_param SCRIPT_FILENAME PATH/$fastcgi_script_name; 说明: $fastcgi_script_name为客户端请求的uri,前面加上资源的目录,即为资源在磁盘中的绝对路径。 例如: php程序放置在/data/nginx/html/xuzhichao/这个目录下,用户访问的URL是http://www.xuzhichao.com/index.php 此时需要把path写为/data/nginx/html/xuzhichao/,才可以找到php程序的路径 fastcgi_param SCRIPT_FILENAME /data/nginx/html/xuzhichao/$fastcgi_script_name;
-
fastcgi_cache_path
配置格式
fastcgi_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];
支持环境:http
参数:
-
path :缓存位置为磁盘上的文件系统路径
-
max_size=size:磁盘path路径中用于缓存数据的缓存空间上限
-
levels=levels:缓存目录的层级数量,以及每一级的目录数量
-
inactive=time:缓存有效时长,默认10分钟,需要在制定的时间满足fastcgi_cache_min_uses次数才会被视为活动缓存
-
key_zone=name:size:设置缓存被调用时的名称和key值在内存中缓存的大小
-
-
fastcgi_cache zone|off
调用指定的缓存空间来缓存数据
支持环境:http, server, location
-
fastcgi_cache_key string
设置nginx服务器在内存中为缓存数据建立索引时使用的关键字
支持环境: http, server, location
示例:fastcgi_cache_key $request_uri;
-
fastcgi_cache_methods GET|HEAD|POST
为哪些请求方法使用缓存
支持环境:http, server, location
默认值: fastcgi_cache_methods GET HEAD;
-
fastcgi_cache_min_uses number
缓存空间中的缓存项在inactive定义的非活动时间内至少要被访问到此处所指定的次数方可被认作活动项。
支持环境:http, server, location
默认值:fastcgi_cache_min_uses 1;
-
fastcgi_cache_valid
不同的响应码各自的缓存时长
配置格式:fastcgi_cache_valid [code …] time;
支持环境:http, server, location
-
fastcgi_keep_conn on|off
收到后端服务器响应后,fastcgi服务器是否关闭连接,建议启用长连接,可提升性能,高于1.1.4版本支持。
启用fastcgi_keep_conn功能可以极大提升nginx性能:
支持环境:http, server, location
默认设置:fastcgi_keep_conn off;
-
fastcgi_hide_header field
隐藏响应头制定信息
-
fastcgi_pass_header field
返回响应头指定信息
默认不会返回status,X-accel等参数。
1.3 nginx与php-fpm部署在一台服务器
1.3.1 php服务器部署
安装php相关程序包,默认base仓库中的php程序包版本较低,此处我们安装7.x系列的PHP软件包。
配置php的yum源:
#方法一:使用rpm包的方式自动生成php的yum源:
#需要安装两个包,第二个包依赖第一个包
[root@nginx01 ~]# rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
[root@nginx01 ~]# rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm
#自动生成的repo文件
[root@nginx01 ~]# cat /etc/yum.repos.d/
webtatic-archive.repo webtatic-testing.repo epel-testing.repo webtatic.repo
#暂时禁用base源,使用webtatic源安装php
[root@nginx01 ~]# yum install php-fpm --disablerepo=base
......
Installed:
php72w-fpm.x86_64 0:7.2.34-1.w7
Dependency Installed:
libargon2.x86_64 0:20161029-3.el7 php72w-common.x86_64 0:7.2.34-1.w7
[root@nginx01 ~]# rpm -q php72w-fpm
php72w-fpm-7.2.34-1.w7.x86_64
#方法二:手动配置yum源,实际测试速度极慢,不建议使用
[root@nginx01 ~]# cat /etc/yum.repos.d/php.repo
[webtatic-php]
name = php repository
baseurl = http://us-east.repo.webtatic.com/yum/el7/x86_64/
gpgcheck = 1
#注意:需要卸载低版本的php-fpm包。
修改php-fpm的配置文件:
php-fpm主要使用的配置文件为/etc/php-fpm.conf 和/etc/php-fpm.d/www.conf 。
[root@nginx01 ~]# grep -Ev "^;|^$" /etc/php-fpm.conf
[global]
pid = /var/run/php-fpm/php-fpm.pid <==守护进程的pid
error_log = /var/log/php-fpm/error.log <==错误日志
daemonize = yes <==表示是否以守护进程的方式运行,定义为no,因为要托管到systemd上
include=/etc/php-fpm.d/*.conf
[root@nginx01 ~]# grep -Ev "^;|^$" /etc/php-fpm.d/www.conf
[www]
user = nginx <==php-fpm启动时使用的用户和用户组,需要和nginx用户保持一致,涉及到文件权限问题。
group = nginx
listen = 127.0.0.1:9000 <==监听的地址和端口
listen.allowed_clients = 127.0.0.1 <==允许客户端从哪个源IP进行访问,注释该行则允许所有客户端地址
pm = dynamic <==进程管理模式,有动态和静态两种,一般使用动态管理方式
pm.max_children = 500 <==静态方式下开启的php-fpm进程数量,动态模式下为php-fpm的最大进程数
pm.start_servers = 100 <==动态模式下php-fpm初始启动的进程数,不能小于最小空闲进程数,不能大于最大进程数
pm.min_spare_servers = 100 <==动态模式下,php-fpm最小子进程数
pm.max_spare_servers = 200 <==动态模式下,php-fpm最大子进程数
pm.max_requests = 500000 <==进程累计请求回收值,会重新生成进程
pm.status_path = /pm_status <==php-fpm状态访问URL
ping.path = /ping <==ping访问的地址,用于测试php-fpm运行状态
ping.response = pong <==ping的返回值pong
slowlog = /var/log/php-fpm/www-slow.log <==慢日志路径
php_admin_value[error_log] = /var/log/php-fpm/www-error.log <==错误日志路径
php_admin_flag[log_errors] = on <==开启错误日志
php_value[session.save_handler] = files <==php session 的存放方式,files表示以文件方式存放
php_value[session.save_path] = /var/lib/php/session <==php session的存放路径,需要运行php-fpm的用户拥有读写权限
php_value[soap.wsdl_cache_dir] = /var/lib/php/wsdlcache
#注意:修改配置文件需要重启php-fpm服务:
[root@nginx01 ~]# systemctl reload php-fpm.service
启动php-fpm服务:
[root@nginx01 ~]# systemctl start php-fpm.service
[root@nginx01 ~]# systemctl enable php-fpm.service
#查看监听的套接字:
[root@nginx01 ~]# ss -ntl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 127.0.0.1:9000 *:*
#查看php-fpm进程,共启动了100个子进程:
[root@nginx01 ~]# ps -ef | grep php-fpm
root 7029 1 0 12:54 ? 00:00:00 php-fpm: master process (/etc/php-fpm.conf)
nginx 7030 7029 0 12:54 ? 00:00:00 php-fpm: pool www
nginx 7031 7029 0 12:54 ? 00:00:00 php-fpm: pool www
nginx 7032 7029 0 12:54 ? 00:00:00 php-fpm: pool www
nginx 7033 7029 0 12:54 ? 00:00:00 php-fpm: pool www
nginx 7034 7029 0 12:54 ? 00:00:00 php-fpm: pool www
nginx 7035 7029 0 12:54 ? 00:00:00 php-fpm: pool www
nginx 7036 7029 0 12:54 ? 00:00:00 php-fpm: pool www
......
准备php的测试代码:
[root@nginx01 ~]# cat /data/nginx/html/xuzhichao/index.php
<?php
phpinfo();
?>
1.3.2 nginx部署
nginx的配置文件如下:
#1.nginx的配置文件如下:
[root@nginx01 ~]# cat /etc/nginx/nginx.conf
http {
......
fastcgi_cache_path /data/nginx/fastcgi_cache levels=1:1:1 keys_zone=fastcgi_cache:250m inactive=10m max_size=1g;
}
[root@nginx01 ~]# cat /etc/nginx/conf.d/xuzhichao.conf
server {
location ~ \.php$ {
#"$document_root"会调用root目录,若不写root指令对应的目录路径,则"$document_root"所对应的值为空.
root /data/nginx/html/xuzhichao;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
#fastcgi_param SCRIPT_FILENAME /data/nginx/html/xuzhichao/$fastcgi_script_name;
include fastcgi_params;
fastcgi_cache fastcgi_cache;
fastcgi_cache_key $request_uri;
fastcgi_cache_methods GET HEAD;
fastcgi_cache_valid 200 301 302 30m;
fastcgi_cache_valid any 5m;
fastcgi_cache_min_uses 1;
fastcgi_keep_conn on;
}
#php-fpm的状态页,无需传递$document_root
location ~ ^/(pm_status|ping)$ {
access_log off;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
include fastcgi_params;
}
}
#2.重启nginx服务:
[root@nginx01 ~]# systemctl reload nginx.service
#3.客户端测试状态页:
[root@xuzhichao ~]# curl http://www.xuzhichao.com/pm_status
pool: www
process manager: dynamic
start time: 27/Jun/2021:15:36:25 +0800
start since: 13
accepted conn: 1
listen queue: 0
max listen queue: 0
listen queue len: 128
idle processes: 99
active processes: 1
total processes: 100
max active processes: 1
max children reached: 0
slow requests: 0
[root@xuzhichao ~]# curl http://www.xuzhichao.com/ping
pong
#4.nginx生成的缓存信息:
[root@nginx01 ~]# ll /data/nginx/fastcgi_cache/1/f/a/e251273eb74a8ee3f661a7af00915af1
-rw------- 1 nginx nginx 61566 Jun 27 15:32 /data/nginx/fastcgi_cache/1/f/a/e251273eb74a8ee3f661a7af00915af1
客户端测试php的主要如下:
1.4 nginx与php-fpm部署在不同的服务器
把php-fpm单独部署在192.168.20.21这台服务器上,192.168.20.20为nginx服务器。
php部署:
#1.php的安装同上节
#2.php的配置文件修改如下:
[root@apache01 ~]# grep "^[a-zA-Z]" /etc/php-fpm.d/www.conf
user = nginx <==用户建议修改为nginx,且uid与nginx服务器上的nginx用户保持一致,不改user,默认为apache也没问题。
group = nginx
listen = 192.168.20.21:9000 <==监听在192.168.20.21地址上
listen.allowed_clients = 192.168.20.20 <==允许客户端IP来访问,也可以注释该行,允许所有客户端访问php-fpm
pm = dynamic
pm.max_children = 500
pm.start_servers = 100
pm.min_spare_servers = 100
pm.max_spare_servers = 200
pm.max_requests = 500000
pm.status_path = /pm_status
ping.path = /ping
ping.response = pong
slowlog = /var/log/php-fpm/www-slow.log
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files
php_value[session.save_path] = /var/lib/php/session
php_value[soap.wsdl_cache_dir] = /var/lib/php/wsdlcache
#3.新建nginx用户:
[root@apache01 ~]# useradd -u 997 nginx
#4.新建php测试代码:目录对nginx需要有读权限
[root@apache01 ~]# mkdir /data/php
[root@apache01 ~]# vim /data/php/index.php
<?php
phpinfo();
?>
[root@apache01 ~]# ll /data/php/index.php
-rw-r--r-- 1 root root 21 Jun 27 16:46 /data/php/index.ph
#5.启动php-fpm服务
[root@apache01 ~]# systemctl start php-fpm
[root@apache01 ~]# ss -ntl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 192.168.20.21:9000 *:*
nginx的配置文件如下:
[root@nginx01 ~]# cat /etc/nginx/conf.d/xuzhichao.conf
server{
location ~ \.php$ {
root /data/nginx/html/xuzhichao;
fastcgi_pass 192.168.20.21:9000; <==php-fpm的地址
fastcgi_index index.php;
#fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME /data/php/$fastcgi_script_name; <==php-fpm服务器的php代码路径
include fastcgi_params;
fastcgi_cache fastcgi_cache;
fastcgi_cache_key $request_uri;
fastcgi_cache_methods GET HEAD;
fastcgi_cache_valid 200 301 302 30m;
fastcgi_cache_valid any 5m;
fastcgi_cache_min_uses 1;
fastcgi_keep_conn on;
}
location ~ ^/(pm_status|ping)$ {
access_log off;
fastcgi_pass 192.168.20.21:9000;
fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
include fastcgi_params;
}
}
[root@nginx01 ~]# systemctl reload nginx.service
客户端测试:
[root@xuzhichao ~]# curl http://www.xuzhichao.com/ping
pong
[root@xuzhichao ~]# curl http://www.xuzhichao.com/pm_status
pool: www
process manager: dynamic
start time: 27/Jun/2021:16:48:31 +0800
start since: 29
accepted conn: 4
listen queue: 0
max listen queue: 0
listen queue len: 128
idle processes: 99
active processes: 1
total processes: 100
max active processes: 2
max children reached: 0
slow requests: 0