我們知道,nginx作為webserver,本身只能處理靜態資源文件;
對於動態的PHP請求,需要調用相應的PHP解釋器來執行;
因此需要配置fastcgi_pass,以實現nginx與php-fpm進程間的通信。
nginx與php-fpm進程間的通信有兩種方式:
- 1、TCP
就是IP加端口;
優點是可以跨服務器;缺點是相比下面的方法要慢;
配置示例:
php-fpm.conf: listen = 127.0.0.1:9000
nginx.conf: fastcgi_pass = 127.0.0.1:9000 - 2、UDS
UDS 就是 UNIX Domain Socket 協議的縮寫;
優點是速度相比TCP要快,因為它不經過傳輸層(5層網絡模型之一);
缺點是隻適用於nginx和php-fpm在同一服務器的場景。
配置示例:
php-fpm.cnf: listen = /run/php/php-fpm.sock
nginx.conf: listen = unix:/run/php/php-fpm.sock
那麼,為什麼UDS比TCP要快?
一般而言,socket編程,是建立在傳輸層基礎上的,就是上面的第一種通信方式,但在Unix系統上,存在一種特殊的socket,這種socket無需使用傳統的IP地址+端口方式,而是直接使用文件來進行程序間的數據交互;
在Unix操作系統中,一切都可以看做是文件,自然包括程序運行的一些信息。因而,可以直接藉助於這些程序運行時產生的文件來進行不同程序之間的數據交互,這就是UDS方式(此種socket只能在unix系統上使用)。
UDS方式,對於程序本身來説,只需讀取和寫入共享的socket文件即可(又分為【StreamSocket-流套接字】和【DatagramSocket-數據包套接字】),可用在兩個沒有關聯關係的進程之間,直接通過socket文件進行數據交互;
時下大火的一種容器技術,docker,和實體機進行數據傳輸和信息交換使用的也正是UDS。
其特點如下:
- 1) 傳輸不經過網絡協議棧(也就是那5層網絡模型),不需要打包拆包,只是數據間的拷貝;
- 2) 由於是在本機通過內核通信,不會丟包也不會出現發送包的次序和接收包的次序不一致的問題;
- 基於以上特點,其傳輸速度更快,有文章稱是TCP的兩倍,沒有深入瞭解,不予置評。
但UDS作為目前比較廣泛使用的IPC機制,傳輸速度更快是肯定的,畢竟網絡協議是為不可靠通訊設計的,而IPC機制本質上是可靠通訊,免去了這些繁瑣的可靠校驗步驟。
UDS與TCP連接方式簡單示意:
UDS方式:
nginx <=> socket <=> php-fpm
TCP本機方式:
nginx <=> socket <=> TCP/IP <=> socket <=> php-fpm
TCP跨服務器方式:
nginx <=> socket <=> TCP/IP <=> 物理層 <=> 路由器 <=> 物理層 <=> TCP/IP <=> socket <=> php-fpm
nginx使用UDS與php-fpm進程間通信的好處:
這種通信方式發生在系統內核裏,不會在網絡中傳播,它不會走到TCP的那一層,直接以stream-socket文件形式通信;
從而避免了頻繁創建TCP短鏈接而導致的 TIME_WAIT 連接過多的問題。
當然了,UDS不能跨服務器也是最明顯的缺點之一,至於如何選擇,需各位看官自己斟酌。
談談php-fpm、fastcgi、cgi之間的關係
CGI (Common Gateway Interface):是一種通用的 Web 服務器和外部應用程序之間進行數據交互的標準協議,它定義了 Web 服務器和外部應用程序之間傳遞數據的格式和規範。在 CGI 模式下,PHP 程序每次請求都需要啓動一個新的進程來處理請求,包括ini,加載擴展配置等,並在請求處理完畢後結束進程,因此效率較低;
FastCGI(Fast Common Gateway Interface):是對 CGI 的一種改進,它可以在進程池中維護多個 PHP 進程,並與 Web 服務器保持長連接,以提高性能。在 FastCGI 模式下,PHP 進程只在啓動時創建一次,並保持運行狀態,不需要每次請求都重新啓動進程;
php-fpm (PHP FastCGI Process Manager):是一個獨立的 PHP 進程管理器,可以管理 FastCGI 模式下的 PHP 進程池,並提供進程調度、進程監控、請求處理等功能。php-fpm 可以獨立於 Web 服務器運行,也可以與 Nginx、Apache 等 Web 服務器配合使用。
結合括號中的英文全拼就比較容易理解了,簡單來説:
CGI 和 FastCGI 是兩個協議,或者叫行業規範,FastCGI 又是 CGI 的升級款方案。
任何語言編寫的程序都可以通過 FastCGI/CGI 協議來提供 Web 服務,不是專屬於PHP的,這樣理解就很清晰了。
php-fpm是對 FastCGI 這種規範的實現,也就是成品(SAPI);
它會啓一個master主進程,初始化執行環境;根據需要(配置文件)fork出多個worker子進程處理請求,這樣就避免了重複勞動,效率自然高;
當worker不夠用時,master可以根據配置預先啓動幾個worker等着;當空閒worker太多時,會幹掉一些,這樣就節約了資源;
當更新配置文件(php.ini)時,新的worker用新的配置,正在處理請求的worker處理完手上的活就下崗,也就實現了平滑重啓;
對了,還有個比較迷惑人的 php-cgi,這裏也一併説下:
php-cgi 是同時實現了 CGI 和 FastCGI 兩種規範協議的成品,它和php-fpm的角色一樣。
CGI 和 FastCGI 都是設計方案,php-cgi 和 php-fpm 都是根據方案製作的成品。
並且,php-cgi是親生的(PHP官方自帶),但它不太好用,比如不能平滑重啓,修改 php.ini 後需 kiil 掉原來的進程才能生效;
php-fpm雖然好用,怎奈不是親生,需要用户手動安裝,俗稱打補丁;
後來佛祖(PHP官方)發現這妖猴有想法,敢打師傅,後面搞不好是個勁敵,索性就收了封個鬥戰勝佛吧,於是在v5.3.2版本之後繼承了進去。