nginx 工作原理
1. Nginx的模塊與工作原理
Nginx由內核和模塊組成,其中,內核的設計非常微小和簡潔,完成的工作也非常簡單,僅僅通過查找配置文件將客戶端請求映射到一個location block(location是Nginx配置中的一個指令,用于URL匹配),而在這個location中所配置的每個指令將會啟動不同的模塊去完成相應的工作。
Nginx的模塊從結構上分為核心模塊、基礎模塊和第三方模塊:
核心模塊:HTTP模塊、EVENT模塊和MAIL模塊基礎模塊:HTTP Access模塊、HTTP FastCGI模塊、HTTP Proxy模塊和HTTP Rewrite模塊,第三方模塊:HTTP Upstream Request Hash模塊、Notice模塊和HTTP Access Key模塊。Nginx的模塊從功能上分為如下三類。
Handlers(處理器模塊)。此類模塊直接處理請求,并進行輸出內容和修改headers信息等操作。Handlers處理器模塊一般只能有一個。Filters (過濾器模塊)。此類模塊主要對其他處理器模塊輸出的內容進行修改操作,最后由Nginx輸出。Proxies (代理類模塊)。此類模塊是Nginx的HTTP Upstream之類的模塊,這些模塊主要與后端一些服務比如FastCGI等進行交互,實現服務代理和負載均衡等功能。圖展示了Nginx模塊常規的HTTP請求和響應的過程。
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的進程模型,可以由下圖來表示:
2. Nginx+FastCGI運行原理
1、什么是 FastCGI
FastCGI是一個可伸縮地、高速地在HTTP server和動態腳本語言間通信的接口。多數流行的HTTP server都支持FastCGI,包括Apache、Nginx和lighttpd等。同時,FastCGI也被許多腳本語言支持,其中就有PHP。
FastCGI是從CGI發展改進而來的。傳統CGI接口方式的主要缺點是性能很差,因為每次HTTP服務器遇到動態程序時都需要重新啟動腳本解析器來執行解析,然后將結果返回給HTTP服務器。這在處理高并發訪問時幾乎是不可用的。另外傳統的CGI接口方式安全性也很差,現在已經很少使用了。
FastCGI接口方式采用C/S結構,可以將HTTP服務器和腳本解析服務器分開,同時在腳本解析服務器上啟動一個或者多個腳本解析守護進程。當HTTP服務器每次遇到動態程序時,可以將其直接交付給FastCGI進程來執行,然后將得到的結果返回給瀏覽器。這種方式可以讓HTTP服務器專一地處理靜態請求或者將動態腳本服務器的結果返回給客戶端,這在很大程度上提高了整個應用系統的性能。
2、Nginx+FastCGI運行原理
Nginx不支持對外部程序的直接調用或者解析,所有的外部程序(包括PHP)必須通過FastCGI接口來調用。FastCGI接口在Linux下是socket(這個socket可以是文件socket,也可以是ip socket)。
wrapper:為了調用CGI程序,還需要一個FastCGI的wrapper(wrapper可以理解為用于啟動另一個程序的程序),這個wrapper綁定在某個固定socket上,如端口或者文件socket。當Nginx將CGI請求發送給這個socket的時候,通過FastCGI接口,wrapper接收到請求,然后Fork(派生)出一個新的線程,這個線程調用解釋器或者外部程序處理腳本并讀取返回數據;接著,wrapper再將返回的數據通過FastCGI接口,沿著固定的socket傳遞給Nginx;最后,Nginx將返回的數據(html頁面或者圖片)發送給客戶端。這就是Nginx+FastCGI的整個運作過程,如圖所示。
所以,我們首先需要一個wrapper,這個wrapper需要完成的工作:
通過調用fastcgi(庫)的函數通過socket和ningx通信(讀寫socket是fastcgi內部實現的功能,對wrapper是非透明的)
調度thread,進行fork和kill
和application(php)進行通信
3、PHP-FPM
FastCGI接口方式在腳本解析服務器上啟動一個或者多個守護進程對動態腳本進行解析,這些進程就是FastCGI進程管理器,或者稱為FastCGI引擎。 spawn-fcgi與PHP-FPM就是支持PHP的兩個FastCGI進程管理器。因此HTTPServer完全解放出來,可以更好地進行響應和并發處理。
Nginx是個輕量級的HTTP server,必須借助第三方的FastCGI處理器才可以對PHP進行解析,因此其實這樣看來nginx是非常靈活的,它可以和任何第三方提供解析的處理器實現連接從而實現對PHP的解析(在nginx.conf中很容易設置)。現在主要用PHP的FastCGI處理器PHP-FPM,它有如下優點:
由于它是作為PHP的patch補丁來開發的,安裝的時候需要和php源碼一起編譯,也就是說編譯到php core中了,因此在性能方面要優秀一些;
同時它在處理高并發方面也優于spawn-fcgi,至少不會自動重啟fastcgi處理器。因此,推薦使用Nginx+PHP/PHP-FPM這個組合對PHP進行解析。
相對Spawn-FCGI,PHP-FPM在CPU和內存方面的控制都更勝一籌,而且前者很容易崩潰,必須用crontab進行監控,而PHP-FPM則沒有這種煩惱。 FastCGI 的主要優點是把動態語言和HTTP Server分離開來,所以Nginx與PHP/PHP-FPM經常被部署在不同的服務器上,以分擔前端Nginx服務器的壓力,使Nginx專一處理靜態請求和轉發動態請求,而PHP/PHP-FPM服務器專一解析PHP動態請求。
4、Nginx+PHP-FPM
PHP-FPM是管理FastCGI的一個管理器,它作為PHP的插件存在,在安裝PHP要想使用PHP-FPM時在老php的老版本(php5.3.3之前)就需要把PHP-FPM以補丁的形式安裝到PHP中,而且PHP要與PHP-FPM版本一致,這是必須的)
PHP-FPM其實是PHP源代碼的一個補丁,旨在將FastCGI進程管理整合進PHP包中。必須將它patch到你的PHP源代碼中,在編譯安裝PHP后才可以使用。 PHP5.3.3已經集成php-fpm了,不再是第三方的包了。PHP-FPM提供了更好的PHP進程管理方式,可以有效控制內存和進程、可以平滑重載PHP配置,比spawn-fcgi具有更多優點,所以被PHP官方收錄了。在./configure的時候帶 –enable-fpm參數即可開啟PHP-FPM。
fastcgi已經在php5.3.5的core中了,不必在configure時添加 –enable-fastcgi了。老版本如php5.2的需要加此項。
當我們安裝Nginx和PHP-FPM完后,配置信息:
PHP-FPM的默認配置php-fpm.conf:
listen_address 127.0.0.1:9000 #這個表示php的fastcgi進程監聽的ip地址以及端口 start_servers min_spare_servers max_spare_serversNginx配置運行php: 編輯nginx.conf加入如下語句:
location ~ \.php$ {//指定了fastcgi進程偵聽的端口,nginx就是通過這里與php交互的root html; fastcgi_pass 127.0.0.1:9000;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地址和端口。
其整體工作流程:
總結
以上是生活随笔為你收集整理的nginx 工作原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CABasicAnimation
- 下一篇: 【STM32H7】第5章 ThreadX