在網頁應用程式開發中,伺服器與後端語言的溝通效率至關重要。傳統 CGI 技術的效能瓶頸促使 FastCGI 的誕生,它透過持久化程式和通訊端通訊,大幅提升了伺服器處理請求的能力。NGINX 作為一款高效能網頁伺服器,完美支援 FastCGI,並能輕鬆整合 PHP 和 Python 等後端語言。透過 fastcgi_pass 指令,NGINX 可以將請求轉發給 FastCGI 程式處理,並利用 upstream 塊實作負載平衡和高用性。除了 FastCGI,NGINX 也支援 uWSGI 和 SCGI 等技術,它們與 FastCGI 的指令和組態方式相似,方便開發者靈活運用。fastcgi_param 指令則用於設定傳遞給 FastCGI 的請求引數,其中 SCRIPT_FILENAMEQUERY_STRING 是必備引數,而 POST 請求還需要額外組態 REQUEST_METHODCONTENT_TYPECONTENT_LENGTH 等引數。NGINX 提供的 fastcgi_params 檔案已包含大部分必要的引數定義,簡化了組態流程。

透過 FastCGI 與 NGINX 運作 PHP 與 Python

在現代網路開發中,高效能的後端處理機制是確保應用程式效能的關鍵。本文將探討如何透過 FastCGI 技術,讓 NGINX 伺服器與 PHP 和 Python 這兩大流行的後端語言進行高效的互動。

CGI 與其侷限性

首先,瞭解一下傳統的 CGI(Common Gateway Interface)技術。CGI 是一種用於描述網頁伺服器(如 NGINX)與應用程式(如 PHP 或 Python)之間資訊交換的協定。當伺服器接收到需要轉發給應用程式的請求時,它會執行相應的應用程式命令,例如 /usr/bin/php。這些請求的詳細資訊(如 User-Agent 標頭和其他請求資訊)會作為命令列引數或環境變數傳遞,而 POST 或 PUT 請求的實際資料則透過標準輸入傳遞。然後,被呼叫的應用程式會將處理過的檔案內容寫入標準輸出,這些內容會被伺服器接收。

雖然 CGI 看起來簡單且高效,但它有一些重大缺點:

  • 每個請求都會啟動一個獨立的程式,因此記憶體和其他上下文資訊在每次請求之間都會遺失。
  • 啟動程式會耗費系統資源。大量同時請求可能會迅速讓伺服器陷入混亂。
  • 設計一個將網頁伺服器和後端應用程式分佈在不同電腦上的架構似乎困難重重。

FastCGI 的改進

為瞭解決 CGI 的問題,開發者們在1990年代中旬開發了 FastCGI。FastCGI 是一種長期存在並且被廣泛採用的標準,幾乎所有現代網頁伺服器都支援這一功能。

FastCGI 相較於 CGI 的主要改進包括:

  • FastCGI 使用持久程式來處理多個請求,而不是為每個請求啟動新的程式。
  • 網頁伺服器和後端應用程式之間透過通訊端(如 TCP 或 Unix 本地 IPC通訊端)進行通訊。因此,伺服器和後端程式可以位於網路上的兩台不同電腦上。
  • 網頁伺服器將客戶端請求轉發給後端應用程式並透過單一連線接收回應。此外,沒有需要建立新連線即可繼續處理額外請求。
  • FastCGI 是根據通訊端協定的,因此可以在任何平台上以任何程式語言實作。

在 NGINX 中組態 FastCGI

FastCGI 與 NGINX 的整合非常簡單。FastCGI 模組是 NGINX 預設構建的一部分,因此不需要手動啟用。以下是一些主要的組態指令:

# 傳送請求到 FastCGI 伺服器
fastcgi_pass hostname:port;

# 傳送請求到 Unix 域通訊端
fastcgi_pass unix:/path/to/fastcgi.socket;

# 使用 upstream 塊
upstream fastcgi {
    server 127.0.0.1:9000;
    server 127.0.0.1:9001;
}
location ~* \.php$ {
    fastcgi_pass fastcgi;
}

內容解密:

上述範例中展示瞭如何將 NGINX 組態為透過 FastCGI 模組將請求轉發給後端應用程式。

  • fastcgi_pass 指令用於指定 FastCGI 伺服器的位置,可以是 TCP socket 或 Unix 域 socket。
  • upstream 塊則可以定義一組快取伺服器以提高負載平衡和高用性。

uWSGI 與 SCGI

除了 FastCGI 外,NGINX 還支援其他兩種相似技術:uWSGI 和 SCGI。

uWSGI 模組允許 NGINX 與實作 uwsgi 協定的應用程式進行通訊,這個協定源自 Web Server Gateway Interface (WSGI)。uWSGI 應該說是最知名且廣泛使用於 Python 應用中的 uwsgi 推動協定。

SCGI(Simple Common Gateway Interface)則是一個較新且更簡單易於實作的 CGI 變體。它最初在2006年推出,並且已經被廣泛應用於各種軟體專案中,包括 Apache、IIS、Java、Cherokee 等。

主要指令

以下列出了一些主要指令及其對應:

FastCGI 模組 uWSGI 模組 SCGI 模組
fastcgi_pass uwsgi_pass scgi_pass
fastcgi_cache uwsgi_cache scgi_cache
fastcgi_temp_path uwsgi_temp_path scgi_temp_path

這些指令的語法和命名方式相似,NGINX 的開發團隊也一直在平行維護這三個模組。因此在組態時可以直接參考 FastCGI 的組態方式來進行調整。

內容解密:

此圖示說明瞭快速 CGI 的工作流程:客戶端傳送請求到 Nginx,Nginx 再將請求轉發給持久化執行中的快速 CGI 程式,由 PHP 或 Python 應用處理後傳回結果給 Nginx。

FastCGI 科技簡介

FastCGI 是一種用於高效處理網頁請求的技術,特別適合與 NGINX 這類別高效能網頁伺服器搭配使用。以下將探討 FastCGI 的各種指令及其在實際應用中的重要性。

FastCGI 指令詳解

fastcgi_param

fastcgi_param 指令用於組態傳遞給 FastCGI 的請求。對於所有 FastCGI 請求來說,SCRIPT_FILENAMEQUERY_STRING 是必須的引數。

fastcgi_param SCRIPT_FILENAME /home/website.com/www$fastcgi_script_name;
fastcgi_param QUERY_STRING $query_string;

針對 POST 請求,還需額外組態 REQUEST_METHODCONTENT_TYPECONTENT_LENGTH

fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;

NGINX 組態目錄中的 fastcgi_params 檔案已經包含了所有必要的引數定義,除了 SCRIPT_FILENAME,這個引數需要根據每個 FastCGI 組態進行指定。

如果引數名稱以 HTTP_ 開頭,則會覆寫客戶端請求中的 HTTP 標頭。此外,可以選擇性地指定 if_not_empty 關鍵字,使 NGINX 僅在指定值非空時傳輸該引數。

fastcgi_bind

fastcgi_bind 指令用於將通訊端繫結到本地 IP 地址,從而指定用於 FastCGI 傳輸的網路介面。

fastcgi_bind IP_address[:port] [transparent | off];

fastcgi_pass_header

fastcgi_pass_header 指令用於指定需要傳遞給 FastCGI 伺服器的額外標頭。

fastcgi_pass_header Authorization;

fastcgi_hide_header

fastcgi_hide_header 指令用於指定需要隱藏的標頭,這些標頭不會被 NGINX 轉發給 FastCGI 伺服器。

fastcgi_hide_header X-Forwarded-For;

fastcgi_index

由於 FastCGI 伺服器不支援自動目錄索引,如果請求的 URI 以 / 結尾,NGINX 會附加 fastcgi_index 值。

fastcgi_index index.php;

fastcgi_ignore_client_abort

這個指令定義了當客戶端中止請求時的行為。如果啟用此指令,NGINX 會忽略中止請求並完成處理;否則,NGINX 會中止處理並終止與 FastCGI 伺服器的通訊。

fastcgi_ignore_client_abort on | off;

fastcgi_intercept_errors

這個指令決定是否讓 NGINX 處理由 gateway 傳回的錯誤或直接將錯誤頁面傳回給客戶端。錯誤處理是透過 NGINX 的 error_page 指令進行的。

fastcgi_intercept_errors on | off;

fastcgi_read_timeout 和 fastcgi_connect_timeout

這兩個指令分別定義了來自 FastCGI 應用程式的回應超時和後端伺服器連線超時。如果超過這些時間限制,NGINX 會傳回相應的 HTTP 錯誤。

fastcgi_read_timeout Numeric value (in seconds);
default: 60 seconds

fastcgi_connect_timeout Numeric value (in seconds);
default: 60 seconds

fastcgi_send_timeout

這個指令定義了向後端伺服器傳送資料的超時時間。此超時時間僅適用於兩次寫操作之間。

fastcgi_send_timeout Numeric value (in seconds);
default: 60 seconds

fastcgi_split_path_info

此指令特別適用於類別似 http://website.com/page.php/param1/param2/ 的 URL。它根據指定的正規表示式拆分路徑資訊。

fastcgi_split_path_info ^(.+\.php)(.*)$;

這會影響兩個變數:$fastcgi_script_name$fastcgi_path_info。它們可以用於進一步引數定義:

fastcgi_param SCRIPT_FILENAME /home/website.com/www$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;

fastcgi_store 和 fastcgi_store_access

fastcgi_store 指令啟用或停用簡單的快取儲存區,將 FastCGI 應用程式的回應儲存為檔案。當同一 URI 再次請求時,檔案會直接從快取儲存區提供,而不是轉發到 FastCGI 應用程式。

fastcgi_store on | off;

fastcfi_store_access 指令定義了快取儲存區中建立檔案的存取許可權:

fastci_store_access [user:r|w|rw] [group:r|w|rw] [all:r|w|rw];
default: user:rw;

其他重要指令

fastci_temp_path 和 fastci_max_temp_file_size

  • fasctg_temp_path: 用於設定臨時檔案和快取檔案存放路徑:

    fastci_temp_path /tmp/nginx_fastci;
    
  • fasctg_max_temp_file_size: 用來設定臨時檔案大小限制:

    fastci_max_temp_file_size Size value; // 預設為1GB,設定為5M:
    

技術選型與案例分析

在選擇使用 FastCGI 技術時,需考慮多個因素:

  • 效能需求:FastCGI 能夠顯著提升高流量網站的效能。
  • 相容性:確保應用程式和伺服器環境支援 FastCGI。
  • 錯誤處理:合理組態錯誤處理機制以提升系統穩定性。
  • 安全性:組態適當的存取許可權和超時設定以防止潛在攻擊。

未來趨勢與改進建議

隨著技術的進步,FastCGI 與其他高效能技術(如 gRPC、WebSocket)結合使用將成為趨勢。此外,結合 AI 和機器學習技術最佳化 FastCGI 的組態和監控也具有巨大潛力。在實務中不斷測試和調整組態以適應不斷變化的流量和需求也是提升系統效能與穩定性的關鍵。

FastCGI 技術探討

FastCGI 是一種高效的 CGI 應用程式介面,能夠顯著提升 Web 伺服器與應用程式之間的溝通效率。在 NGINX 中,FastCGI 可以與多種語言(如 PHP 和 Python)結合使用,提供高效的伺服器組態。本文將探討 FastCGI 的核心指令、快取與緩衝技術,並以實際案例說明如何在 NGINX 中組態 PHP 與 Python。

FastCGI 主要指令

FastCGI 提供多種指令來控制與調整其行為。以下是一些關鍵指令及其應用:

fastcgi_ignore_headers

fastcgi_ignore_headers 指令可以防止 NGINX 處理來自後端伺服器回應的特定標頭。這些標頭包括 X-Accel-RedirectExpiresCache-Control 等。這些標頭通常用於控制快取行為和重定向。

fastcgi_ignore_headers header1 [header2...];

例如:

fastcgi_ignore_headers Expires Cache-Control;

這樣可以讓 NGINX 忽略後端伺服器傳回的 ExpiresCache-Control 標頭,從而避免不必要的快取行為。

fastcgi_next_upstream

當 FastCGI 與上游伺服器群組(upstream block)連線時,這個指令定義了在什麼情況下應該放棄當前請求並轉向下一個上游伺服器。它可以接受多種值,如錯誤、超時、無效標頭等。

fastcgi_next_upstream error timeout invalid_header http_500 http_503 http_403 http_404 http_429;

例如:

fastcgi_next_upstream error timeout http_504;

這樣組態表示當發生錯誤或超時時,NGINX 會轉向下一個上游伺服器。

fastcgi_next_upstream_timeout

這個指令定義了在使用 fastcgi_next_upstream 指令時的超時時間。設為 0 則停用此功能。

fastcgi_next_upstream_timeout 10s;

fastcgi_next_upstream_tries

這個指令定義了在傳回錯誤之前,NGINX 最多嘗試連線的上游伺服器次數。

fastcgi_next_upstream_tries 3;

fastcgi_catch_stderr

這個指令允許攔截並記錄錯誤訊息到 NGINX 的錯誤日誌中。

fastcgi_catch_stderr "PHP Fatal error:";

fastcgi_keep_conn

當設為 on 時,NGINX 會保持與 FastCGI 伺服器的連線,從而減少開銷。

fastcgi_keep_conn on;

fastcgi_force_ranges

當設為 on 時,NGINX 會啟用對來自 FastCGI 單元後端回應的位元組範圍支援。

fastcgi_force_ranges on;

fastcgi_limit_rate

這個指令允許限制 NGINX 下載來自 FastCGI 單元後端回應的速率(位元組/秒)。

fastcgi_limit_rate 1024; # 每秒限制為 1024 位元組

FastCGI 快取與緩衝

FastCGI 快取和緩衝是提升伺服器效能的重要手段。以下是一些相關指令及其應用:

fastcgi_cache

這個指令用於設定 FastCGI 快取區域。透過快取常見請求的結果,可以顯著提升伺服器效能。

fastcgi_cache phpcache;

fastcgi_cache_key

這個指令定義了快取鍵,通常包含請求方案、主機名和請求 URI。

fastcgi_cache_key "$scheme$host$request_uri";

fastcgi_cache_path

這個指令定義了快取路徑和引數,如層級、快取區域大小等。

fastcgi_cache_path /tmp/cache levels=1:2 keys_zone=phpcache:10m inactive=30m max_size=500M;

NGINX 與 PHP 的組態例項

以下是一個完整的 NGINX 組態範例,展示瞭如何使用 FastCGI 與 PHP 語言:

server {
    server_name website.com;
    location ~* \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME /home/website.com/www$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_script_name;
        include fastcgi_params;
        include fastcgi_cache; # 包含快取組態
    }
}

PHP-FPM 的角色

PHP-FPM 是 PHP-FastCGI Process Manager 的縮寫,它是 PHP 的程式管理器,能夠顯著提升 PHP 與 Web 伺服器之間的互動效率。以下是 PHP-FPM 的一些主要特性:

  • 自動守護程式化(daemonize),將 PHP 轉換為後台程式。
  • 在受限環境中執行指令碼。
  • 改善日誌記錄、IP 地址限制、池分離等功能。

Python 與 FastCGI 的結合

除了 PHP 外,Python 也可以透過 FastCGI 與 NGINX 配合使用。Python 有多種 Web 框架支援 FastCGI 模式,如 Flask 和 Django。以下是 Flask 框架的一個簡單組態範例:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

在 NGINX 中組態 Flask 應用:

server {
    server_name website.com;
    location / {
        proxy_pass http://127.0.0.1:5000;
    }
}