Nginx 啟動原理與模型
阿新 • • 發佈:2018-07-18
操作 sele -s 這樣的 影響 非阻塞 select images load Nginx 在啟動後,在 unix 系統中會以 daemon 的方式在後臺運行,後臺進程包含一個 master 進程和多個 worker 進程。
master 進程主要用來管理 worker 進程,包含:接收來自外界的信號,向各 worker 進程發送信號,監控 worker 進程的運行狀態,當 worker 進程退出後(異常情況下),會自動重新啟動新的 worker 進程。
多個 worker 進程之間是對等的,他們同等競爭來自客戶端的請求,各進程互相之間是獨立的。worker 進程的個數是可以設置的,一般我們會設置與機器cpu核數一致。
kill -HUP pid,則是告訴 Nginx,從容地重啟 Nginx,此服務是不中斷。master 進程在接收到 HUP 信號後是怎麽做的呢?首先 master 進程在接到信號後,會先重新加載配置文件,然後再啟動新的 worker 進程,並向所有老的 worker 進程發送信號,告訴他們可以光榮退休了。新的 worker 在啟動後,就開始接收新的請求,而老的 worker 在收到來自 master 的信號後,就不再接收新的請求,並且在當前進程中的所有未處理完的請求處理完成後,再退出。
Nginx 在 0.8 版本之後,引入了一系列命令行參數,來方便我們管理。比如,./nginx -s reload,就是來重啟 Nginx,./nginx -s stop,就是來停止 Nginx 的運行。如何做到的呢?我們還是拿 reload 來說,我們看到,執行命令時,我們是啟動一個新的 Nginx 進程,而新的 Nginx 進程在解析到 reload 參數後,就知道我們的目的是控制 Nginx 來重新加載配置文件了,它會向 master 進程發送信號,然後接下來的動作,就和我們直接向 master 進程發送信號一樣了。
- worker 進程又是如何處理請求的呢?前面有提到,worker 進程之間是平等的,每個進程,處理請求的機會也是一樣的。當我們提供 80 端口的 http 服務時,一個連接請求過來,每個進程都有可能處理這個連接,怎麽做到由一個worker來處理呢?
- Nginx 采用這種進程模型有什麽好處呢?當然,好處肯定會很多了。首先,對於每個 worker 進程來說,獨立的進程,不需要加鎖,所以省掉了鎖帶來的開銷,同時在編程以及問題查找時,也會方便很多。其次,采用獨立的進程,可以讓互相之間不會影響,一個進程退出後,其它進程還在工作,服務不會中斷,master 進程則很快啟動新的 worker 進程。當然,worker 進程的異常退出,肯定是程序有 bug 了,異常退出,會導致當前 worker 上的所有請求失敗,不過不會影響到所有請求,所以降低了風險。當然,好處還有很多,大家可以慢慢體會。
- Nginx 采用多 worker 的方式來處理請求,每個 worker 裏面只有一個主線程,那能夠處理的並發數很有限啊,多少個 worker 就能處理多少個並發,何來高並發呢?非也,這就是 Nginx 的高明之處,Nginx 采用了異步非阻塞的方式來處理請求,也就是說,Nginx 是可以同時處理成千上萬個請求的。想想 apache 的常用工作方式(apache 也有異步非阻塞版本,但因其與自帶某些模塊沖突,所以不常用),每個請求會獨占一個工作線程,當並發數上到幾千時,就同時有幾千的線程在處理請求了。這對操作系統來說,是個不小的挑戰,線程帶來的內存占用非常大,線程的上下文切換帶來的 cpu 開銷很大,自然性能就上不去了,而這些開銷完全是沒有意義的
9.為什麽 Nginx 可以采用異步非阻塞的方式來處理呢,或者異步非阻塞到底是怎麽回事呢?在 Nginx 裏面,最忌諱阻塞的系統調用了。不要阻塞,那就非阻塞嘍。非阻塞就是,事件沒有準備好,馬上返回 EAGAIN,告訴你,事件還沒準備好呢,你慌什麽,過會再來吧。好吧,你過一會,再來檢查一下事件,直到事件準備好了為止,在這期間,你就可以先去做其它事情,然後再來看看事件好了沒。雖然不阻塞了,但你得不時地過來檢查一下事件的狀態,你可以做更多的事情了,但帶來的開銷也是不小的。所以,才會有了異步非阻塞的事件處理機制,具體到系統調用就是像 select/poll/epoll/kqueue 這樣的系統調用。它們提供了一種機制,讓你可以同時監控多個事件,調用他們是阻塞的,但可以設置超時時間,在超時時間之內,如果有事件準備好了,就返回。
10.知道了 Nginx 為什麽會選擇這樣的進程模型與事件模型了。對於一個基本的 Web 服務器來說,事件通常有三種類型,網絡事件、信號、定時器。
Nginx 啟動原理與模型