Nginx本身不會對PHP進行解析,終端對PHP頁面的請求將會被Nginx交給FastCGI進程監聽的IP位址及端口,由php-fpm作為動態解析伺服器處理,最後將處理結果再返回給nginx。其實,Nginx就是一個反向代理伺服器。 Nginx透過反向代理功能將動態請求轉向後端php-fpm,從而實現對PHP的解析支持,這就是Nginx實現PHP動態解析的原理。
Nginx不支援外部程式的直接呼叫或解析,所有的外部程式(包括PHP)必須透過FastCGI介面來呼叫。 FastCGI介面在Linux下是socket(這個socket可以是檔案socket,也可以是ip socket)。為了呼叫CGI程序,還需要一個FastCGI的wrapper(wrapper可以理解為用於啟動另一個程式的程式),這個wrapper綁定在某個固定socket上,例如連接埠或檔案socket。當Nginx將CGI請求發送給這個socket的時候,透過FastCGI接口,wrapper接收到請求,然後派生出一個新的線程,這個線程調用解釋器或者外部程序處理腳本並讀取返回數據;接著,wrapper再將傳回的資料透過FastCGI接口,沿著固定的socket傳遞給Nginx;最後,Nginx將傳回的資料傳送給客戶端。
經典的模型就是Nginx中所使用的Master-Worker多進程非同步驅動模型。
父進程創建socket,bind、listen後,透過fork創建多個子進程,每個子進程繼承了父進程的socket,呼叫accpet開始監聽等待網路連線。這時候有多個進程同時等待網路的連線事件,當這個事件發生時,這些進程被同時喚醒,就是「驚群」。進程被喚醒,需要進行內核重新調度,這樣每個進程同時去響應這一個事件,而最終只有一個進程能處理事件成功,其他的進程在處理該事件失敗後重新休眠或其他。
其實在Linux2.6版本以後,核心核心已經解決了accept()函數的「驚群」問題,當核心接收到一個客戶連線後,只會喚醒等待佇列上的第一個行程或線程。
Nginx中使用accept_mutexmutex互斥鎖解決這個問題,具體措施有使用全域互斥鎖,每個子程序在epoll_wait()之前先去申請鎖,申請到則繼續處理,獲取不到則等待,並設定了一個負載平衡的演算法(當某一個子程序的任務量達到總設定量的7/8時,則不會再嘗試去申請鎖)來平衡各個行程的任務量。
現在我們對驚群及 Nginx 的處理總結如下:
accept 不會有驚群,epoll_wait 才會。
Nginx 的 accept_mutex,並不是解決 accept 驚群問題,而是解決 epoll_wait 驚群問題。
說Nginx 解決了 epoll_wait 驚群問題,也是不對的,它只是控制是否將監聽套接字加入到epoll 中。監聽套接字只在一個子進程的 epoll 中,當新的連線來到時,其他子進程當然不會驚醒了。
簡單了說,就是同一時刻只允許一個nginx worker在自己的epoll中處理監聽句柄。它的負載平衡也很簡單,當達到最大connection的7/8時,本worker不會去試圖拿accept鎖,也不會去處理新連接,這樣其他nginx worker進程就更有機會去處理監聽句柄,建立新連線了。而且,由於timeout的設定,使得沒有拿到鎖的worker進程,去拿鎖的頻繁更高。
nginx 多進程模型真的沒有鎖了嗎?其實還是有一個的:ngx_accept_mutex。
nginx是一個多進程程序,80埠為各worker進程共享,每當有連線到來時,勢必多個worker進程都要爭著去回應,這也就是所謂的驚群現象。
當核心accept一個連結時,會喚醒所有等待中的進程,但實際上只有一個進程能獲取連接,其它的進程都被無效喚醒,這種無效喚醒無疑將會增加應用的開銷。為此,nginx提供了一把accept鎖避免九子奪嫡的悲劇。
ngx_accept_mutex的作用也就是讓那些當前負載嚴重
的worker進程主動放棄對新到來的請求的處理,提高
應用整體的喚醒效率,進而提升應用的整體性能。
proxy_cache
upstream
fastcgi_pass
location
非標準狀態碼444表示關閉連線且不給客戶端發送回應頭。
nginx -s reload 指令載入修改後的設定檔,指令下達後發生下列事件
1. Nginx的master進程檢查設定檔的正確性,若是錯誤則回傳錯誤訊息,nginx繼續採用原始設定檔進行工作(因為worker未受到影響)
##2. Nginx啟動新的worker進程,採用新的設定檔3. Nginx將新的請求指派新的worker進程4. Nginx等待先前的worker進程的全部請求已經都返回後,關閉相關worker進程5. 重複上面過程,知道全部舊的worker進程都被關閉掉以上流程是參考nginx官方的相關文件後得出。 以 proxy_next_upstream為例, 一般的設定如下:proxy_next_upstream http_504 timeout;這個指令有兩個作用:總的來說, nginx對於 error, timeout, invalide_header 都默認失敗, 其他的行為如果想當作失敗,需要加入類似 proxy_next_upstream之類的指令裡面的。 其中 http_403, http_404均不認識是失敗。
Ngxin把客戶端請求的處理過程分割成11個階段
#1 NGX_HTTP_POST_READ_PHASE: 讀取請求內容階段
##2 NGX_WRTP_SER : Server請求位址重寫階段
#3 NGX_HTTP_FIND_CONFIG_PHASE: 設定尋找階段
#4 NGX_HTTP_REWRITE_PHASE: 地址重寫提交階段
#6 NGX_HTTP_PREACCESS_PHASE: 存取權檢查準備階段
#7 NGX_HTTP_ACCESS_PHASE: 檢查提交階段
#9 NGX_HTTP_TRY_FILES_PHASE: 設定項目try_files處理階段
#10 NGX_HTTP_CONTENT_PHASE: 日誌模組處理階段
Nginx的請求處理流程
#1 Nginx如何確認由哪個server處理該請求?
1. 利用ip + port 確認監聽該ip和連接埠的server。
2. 根據請求中的host首部確認選擇那個server處理該請求。
3. 如果沒有符合任何server,則把該請求轉給預設(default)server處理,
一般而言,不加任何設定的話,設定檔中順序出現的第一個server當
default server。
4. 可以對listen指令使用default_server標誌,去設定某個server為
default server。
#2 Nginx如何根據host首部來匹配server?
Nginx主要是透過比較server中的server_name和host首部來匹配server的。
比較順序如下圖所示:
1. 精確的name;
2. 最長配對的前導通配符name(如:*.zhidao.baidu.com) ;
3. 最長的後導通配符name(如:zhidao.baidu.*);
#3 初始化http請求,http請求的11個階段
location匹配指令
~ 波浪線表示執行一個正規匹配,區分大小寫。
~* 表示執行一個正規匹配,不區分大小寫。
^~ ^~表示普通字元匹配,如果該選項匹配,只匹配該選項,不匹配別的選項,一般用來匹配目錄。
= 進行普通字元精確比對。
@ "@" 定義一個命名的 location,使用在內部導向時,例如 error_page,try_files。
範例:
#請求URI範例:
/ -> 符合configuration A
/documents/document.html -> 符合configuration B
/images/1.gif -> ; 符合configuration C
/documents/1.jpg ->符合configuration D
以上是nginx相關知識點總結分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!