我們知道進程和執行緒會消耗記憶體和其它系統資源,同時他們需要進行上下文切換。大多數現代伺服器可以同時處理成千上萬的進程或線程,但是當記憶體耗盡時,效能將下降,同時,在高IO負載時,將會出現頻繁的上下文切換。
處理網路的常規方法是為每個連接創建一個進程或線程,這種方式容易實現,但是擴展困難。
那麼Nginx是怎麼做的呢? How Does NGINX Work?
nginx 啟動後,會有一個 master 進程和多個 worker 進程。 master 進程主要用來管理worker進程,包含:接收來自外界的訊號,向各worker 進程發送訊號,監控worker 進程的運作狀態,當worker進程退出後(異常),會自動重新啟動新的worker 進程。而基本的網路事件,則是放在 worker 進程中來處理了。多個 worker 進程之間是對等的,他們同等競爭來自客戶端的請求,各進程相互之間是獨立的。一個請求,只可能在一個worker 進程中處理,一個 worker 進程,不可能處理其它進程的請求。 worker 進程的數量是可以設定的,一般我們會設定與機器 cpu 核數一致,這裡面的原因與 nginx 的進程模型以及事件處理模型是分不開的。 nginx 的流程模型,可以由下圖來表示:
可以看到,worker 進程是由master 來管理的。 master 流程會接收來自外界發來的訊號,再根據訊號做不同的事情。所以我們要控制 nginx,只需要向 master 進程發送訊號就行了。例如, ./nginx -s reload,就是來重啟nginx, 該命令會向master 進程發送信號,首先master 進程在接到信號後,會先重新加載配置文件,然後再啟動新的進程,並向所有老的進程發送訊號,告訴他們可以光榮退休了。新的進程在啟動後,就開始接收新的請求,而老的進程在收到來自master 的信號後,就不再接收新的請求,並且在當前進程中的所有未處理完的請求處理完成後,再退出。
那麼,worker 流程又是如何處理請求的呢?
我們前面有提到,worker 進程之間是平等的,每個進程,處理請求的機會也是一樣的。當我們提供 80 連接埠的 http 服務時,一個連接請求過來,每個進程都有可能處理這個連接,怎麼做到的呢?首先,每個worker 進程都是從master 進程fork 過來,在master 進程裡面,先建立好需要listen 的socket 之後,然後再fork 出多個worker 進程,這樣每個worker 進程都可以去accept 這個socket(當然不是同一個socket,只是每個進程的這個socket 會監控在同一個ip 位址與端口,這個在網路協定裡面是允許的)。 nginx提供了一個 accept_mutex 這個東西,從名字上,我們可以看這是一個加在 accept 上的一把共享鎖。有了這把鎖之後,同一時刻,就只會有一個程序在 accpet 連線。 accept_mutex 是一個可控選項,我們可以顯示地關掉,預設是打開的。當一個 worker 程序在 accept 這個連接之後,就開始讀取請求,解析請求,處理請求,產生資料後,再返回給客戶端,最後才斷開連接,這樣一個完整的請求就是這樣的了。我們可以看到,一個請求,完全由 worker 進程來處理,而且只在一個 worker 進程中處理。
那麼,nginx 採用這種流程模型有什麼好處呢?
1)每個 worker 進程獨立,不需要加鎖,省掉了鎖開銷,程式簡單。
2)進程相互獨立不影響,一個進程退出(例如出現異常)後,其它進程照常工作,服務不會中斷。
3)沒有上下文切換,減少無謂的系統開銷
Nginx採用事件驅動處理機制,在linux裡面就是epoll這樣的系統呼叫。可以同時監控多個事件,可以設定超時時間,在超時時間之內,如果有事件準備好了,就回傳準備好的事件。這樣,只要有事件準備好了,我們就去處理它,只有當所有事件都沒準備好時,才在 epoll 阻塞等待。這樣,我們就可以進行高並發處理,我們在請求間進行不斷地切換,切換是因為事件未準備好,而主動讓出的。這裡的切換是沒有任何代價,可以簡單理解為循環處理多個準備好的事件。
與多線程相比,這種事件處理方式是有很大的優勢的,不需要創建線程,每個請求佔用的內存也很少,沒有上下文切換,事件處理非常的輕量級。並發數再多也不會導致無謂的資源浪費(上下文切換)。更多的並發數,只是會佔用更多的記憶體而已,這也是 nginx 效能高效的主要原因。
以下摘自Nginx官網:
When an NGINX server is active, only the worker processes are busy. Each worker process handles multiple connections in a non-blocking fashion, reducing the number of context switches.
Each worker process is single-threaded and runs independently, grabbing new connections and processing them. The processes can communicate using shared memory for shared cache data, session persistence data, and 其他itialized with the NGINX configuration and is provided with a set of listen sockets by the master process.
以上就介紹了Nginx2:工作機制,包括了方面的內容,希望對PHP教程有興趣的朋友有所幫助。