Nginx與PHP工做原理

Nginx的工做原理


1.Nginx的模塊與工做原理

Nginx由內核和模塊組成,其中,內核的設計很是微小和簡潔,完成的工做也很是簡單,僅僅經過查找配置文件將客戶端請求映射到一個location block(location是Nginx配置中的一個指令,用於URL匹配),而在這個location中所配置的每一個指令將會啓動不一樣的模塊去完成相應的工做。php



Nginx的模塊從結構上分爲核心模塊、基礎模塊和第三方模塊:html

核心模塊:HTTP模塊、EVENT模塊和MAIL模塊linux

基礎模塊:HTTP Access模塊、HTTP FastCGI模塊、HTTP Proxy模塊和HTTP Rewrite模塊,nginx

第三方模塊:HTTP Upstream Request Hash模塊、Notice模塊和HTTP Access Key模塊。後端

用戶根據本身的須要開發的模塊都屬於第三方模塊。正是有了這麼多模塊的支撐,Nginx的功能纔會如此強大。瀏覽器

Nginx的模塊從功能上分爲以下三類。
安全

Handlers(處理器模塊)。此類模塊直接處理請求,並進行輸出內容和修改headers信息等操做。Handlers處理器模塊通常只能有一個。服務器

Filters (過濾器模塊)。此類模塊主要對其餘處理器模塊輸出的內容進行修改操做,最後由Nginx輸出。網絡

Proxies (代理類模塊)。此類模塊是Nginx的HTTP Upstream之類的模塊,這些模塊主要與後端一些服務好比FastCGI等進行交互,實現服務代理和負載均衡等功能。併發

下圖展現了Nginx模塊常規的HTTP請求和響應的過程。



Nginx自己作的工做實際不多,當它接到一個HTTP請求時,它僅僅是經過查找配置文件將這次請求映射到一個location block ,所以location中所配置的各個指令則會啓動不一樣的模塊去完成工做,所以模塊能夠看作Nginx真正的勞動工做者。一般一個location中的指令會涉及一個handler模塊和多個filter模塊(固然,多個location能夠複用同一個模塊)。handler模塊負責處理請求,完成響應內容的生成,而filter模塊對響應內容進行處理。

Nginx的模塊直接被編譯進Nginx,所以屬於靜態編譯方式。啓動Nginx後,Nginx的模塊被自動加載,不像Apache,首先將模塊編譯爲一個so文件,而後在配置文件中指定是否進行加載。在解析配置文件時,Nginx的每一個模塊都有可能去處理某個請求,可是同一個處理請求只能由一個模塊來完成。

2.Nginx的進程模型

在工做方式上,Nginx分爲單工做進程和多工做進程兩種模式。在單工做進程模式下,除主進程外,還有一個工做進程,工做進程是單線程的;在多工做進程模式下,每一個工做進程包含多個線程。Nginx默認爲單工做進程模式。

Nginx在啓動後,會有一個master進程和多個worker進程。

master進程

主要用來管理worker進程,包含:接收來自外界的信號,向各worker進程發送信號,監控worker進程的運行狀態,當worker進程退出後(異常狀況下),會自動從新啓動新的worker進程。

master進程充當整個進程組與用戶的交互接口,同時對進程進行監護。它不須要處理網絡事件,不負責業務的執行,只會經過管理worker進程來實現重啓服務、平滑升級、更換日誌文件、配置文件實時生效等功能。

咱們要控制nginx,只須要經過kill向master進程發送信號就好了。好比kill -HUP pid,則是告訴nginx,從容地重啓nginx,咱們通常用這個信號來重啓nginx,或從新加載配置,由於是從容地重啓,所以服務是不中斷的。master進程在接收到HUP信號後是怎麼作的呢?首先master進程在接到信號後,會先從新加載配置文件,而後再啓動新的worker進程,並向全部老的worker進程發送信號,告訴他們能夠光榮退休了。新的worker在啓動後,就開始接收新的請求,而老的worker在收到來自master的信號後,就再也不接收新的請求,而且在當前進程中的全部未處理完的請求處理完成後,再退出。固然,直接給master進程發送信號,這是比較老的操做方式,nginx在0.8版本以後,引入了一系列命令行參數,來方便咱們管理。好比,./nginx -s reload,就是來重啓nginx,./nginx -s stop,就是來中止nginx的運行。如何作到的呢?咱們仍是拿reload來講,咱們看到,執行命令時,咱們是啓動一個新的nginx進程,而新的nginx進程在解析到reload參數後,就知道咱們的目的是控制nginx來從新加載配置文件了,它會向master進程發送信號,而後接下來的動做,就和咱們直接向master進程發送信號同樣了。

worker進程:

而基本的網絡事件,則是放在worker進程中來處理了。多個worker進程之間是對等的,他們同等競爭來自客戶端的請求,各進程互相之間是獨立的。一個請求,只可能在一個worker進程中處理,一個worker進程,不可能處理其它進程的請求。worker進程的個數是能夠設置的,通常咱們會設置與機器cpu核數一致,這裏面的緣由與nginx的進程模型以及事件處理模型是分不開的。

worker進程之間是平等的,每一個進程,處理請求的機會也是同樣的。當咱們提供80端口的http服務時,一個鏈接請求過來,每一個進程都有可能處理這個鏈接,怎麼作到的呢?首先,每一個worker進程都是從master進程fork過來,在master進程裏面,先創建好須要listen的socket(listenfd)以後,而後再fork出多個worker進程。全部worker進程的listenfd會在新鏈接到來時變得可讀,爲保證只有一個進程處理該鏈接,全部worker進程在註冊listenfd讀事件前搶accept_mutex,搶到互斥鎖的那個進程註冊listenfd讀事件,在讀事件裏調用accept接受該鏈接。當一個worker進程在accept這個鏈接以後,就開始讀取請求,解析請求,處理請求,產生數據後,再返回給客戶端,最後才斷開鏈接,這樣一個完整的請求就是這樣的了。咱們能夠看到,一個請求,徹底由worker進程來處理,並且只在一個worker進程中處理。worker進程之間是平等的,每一個進程,處理請求的機會也是同樣的。當咱們提供80端口的http服務時,一個鏈接請求過來,每一個進程都有可能處理這個鏈接,怎麼作到的呢?首先,每一個worker進程都是從master進程fork過來,在master進程裏面,先創建好須要listen的socket(listenfd)以後,而後再fork出多個worker進程。全部worker進程的listenfd會在新鏈接到來時變得可讀,爲保證只有一個進程處理該鏈接,全部worker進程在註冊listenfd讀事件前搶accept_mutex,搶到互斥鎖的那個進程註冊listenfd讀事件,在讀事件裏調用accept接受該鏈接。當一個worker進程在accept這個鏈接以後,就開始讀取請求,解析請求,處理請求,產生數據後,再返回給客戶端,最後才斷開鏈接,這樣一個完整的請求就是這樣的了。咱們能夠看到,一個請求,徹底由worker進程來處理,並且只在一個worker進程中處理。

nginx的進程模型,能夠由下圖來表示:

3.什麼是FastCGI

FastCGI是一個可伸縮地、高速地在HTTP server和動態腳本語言間通訊的接口。多數流行的HTTP server都支持FastCGI,包括Apache、Nginx和lighttpd等。同時,FastCGI也被許多腳本語言支持,其中就有PHP

FastCGI是從CGI發展改進而來的。

CGI工做原理和缺點:

每次HTTP服務器遇到動態程序時都須要從新啓動腳本解析器來執行解析,而後將結果返回給HTTP服務器。

這在處理高併發訪問時幾乎是不可用的。另外傳統的CGI接口方式安全性也不好,如今已經不多使用了。

FastCGI工做原理和優勢:

FastCGI接口方式採用C/S結構,能夠將HTTP服務器和腳本解析服務器分開,同時在腳本解析服務器上啓動一個或者多個腳本解析守護進程。當HTTP服務器每次遇到動態程序時,能夠將其直接交付給FastCGI進程來執行,而後將獲得的結果返回給瀏覽器。

這種方式可讓HTTP服務器專注地處理靜態請求或者將動態腳本服務器的結果返回給客戶端,這在很大程度上提升了整個應用系統的性能。

另外fastCGI程序與CGI程序與服務器的交互方式也不一樣

CGI程序經過環境變量、命令行、標準輸入輸出進行交互,所以CGI程序進程必須與服務器進程在同一臺物理計算機上,而fastCGI程序與服務器進程經過網絡鏈接交互,所以fastCGI程序能夠分佈在不一樣的計算機上,這不但能夠提升性能,同時也提升了系統的擴展能力。

4.什麼是PHP-fpm

PHP-FPM是管理FastCGI的一個管理器,它做爲PHP的插件存在,在安裝PHP要想使用PHP-FPM時在老php的老版本(php5.3.3以前)就須要把PHP-FPM以補丁的形式安裝到PHP中,並且PHP要與PHP-FPM版本一致,這是必須的)

PHP-FPM是FastCGI的實現,任何實現了FastCGI協議的Web Server都可以與之通訊。FPM之於標準的FastCGI,也提供了一些加強功能,具體能夠參考官方文檔:PHP: FPM Installation。

FPM是一個PHP進程管理器,包含master進程和worker進程兩種進程:master進程只有一個,負責監聽端口,接收來自Web Server的請求,而worker進程則通常有多個(具體數量根據實際須要配置),每一個進程內部都嵌入了一個PHP解釋器,是PHP代碼真正執行的地方,下圖是我本機上fpm的進程狀況,1一個master進程,3個worker進程:


從FPM接收到請求,處處理完畢,其具體的流程以下:

1.FPM的master進程接收到請求

2.master進程根據配置指派特定的worker進程進行請求處理,若是沒有可用進程,返回錯誤,這也是咱們配合Nginx遇到502錯誤比較多的緣由。

3.worker進程處理請求,若是超時,返回504錯誤

4.請求處理結束,返回結果

5.FastCGI子進程接着等待並處理來自FastCGI進程管理器(運行在 WebServer中)的下一個鏈接


4.那麼Nginx,PHP-fpm和FastCGI是怎麼的運行流程呢?

Nginx不支持對外部程序的直接調用或者解析,全部的外部程序(包括PHP)必須經過FastCGI接口來調用。FastCGI接口在Linux下是socket(這個socket能夠是文件socket,也能夠是ip socket)。

1)、FastCGI進程管理器php-fpm自身初始化,啓動主進程php-fpm和啓動start_servers個CGI 子進程。

主進程php-fpm主要是管理fastcgi子進程,監聽9000(這個根據配置文件的監聽端口改變而變)端口。

fastcgi子進程等待來自Web Server的鏈接。

2)、當客戶端請求到達Web Server Nginx是時,Nginx經過location指令,將全部以php爲後綴的文件都交給127.0.0.1:9000來處理,即Nginx經過location指令,將全部以php爲後綴的文件都交給127.0.0.1:9000來處理。

3)FastCGI進程管理器PHP-FPM選擇並鏈接到一個子進程CGI解釋器。Web server將CGI環境變量和標準輸入發送到FastCGI子進程。

4)、FastCGI子進程完成處理後將標準輸出和錯誤信息從同一鏈接返回Web Server。當FastCGI子進程關閉鏈接時,請求便告處理完成。

5)、FastCGI子進程接着等待並處理來自FastCGI進程管理器(運行在 WebServer中)的下一個鏈接。

以上流程是根據下方配置文件來講明:


PHP-FPM的默認配置php-fpm.conf:

listen_address 127.0.0.1:9000 #這個表示php的fastcgi進程監聽的ip地址以及端口

start_servers

min_spare_servers

max_spare_servers

Nginx配置運行php:編輯nginx.conf加入以下語句:

location ~ .php$ {

root html;

fastcgi_pass 127.0.0.1:9000;指定了fastcgi進程偵聽的端口,nginx就是經過這裏與php交互的

fastcgi_index index.php;

include fastcgi_params;

fastcgi_param SCRIPT_FILENAME /usr/local/nginx/html$fastcgi_script_name;

}

Nginx經過location指令,將全部以php爲後綴的文件都交給127.0.0.1:9000來處理,而這裏的IP地址和端口就是FastCGI進程監聽的IP地址和端口。


參考:

http://www.jianshu.com/p/d0b858ed5030

http://www.jianshu.com/p/a51a2d70e096

若有不正確之處,麻煩指出改正。謝謝~

原文地址: https://www.jianshu.com/p/df89b530db89
相關文章
相關標籤/搜索