1. 程式人生 > 其它 >WEB服務與NGINX(21)- nginx 的fastcgi反向代理功能

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可以在其互動式視窗直接執行。

    官方網站

    官網:http://www.php.net/

  • 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