nginx在啟動後,在unix系統中會以daemon的方式在背景運作,背景程序包含一個master程序和多個worker程序。
當然nginx也是支援多線程的方式的,隻是我們主流的方式還是多程序的方式,也是nginx的預設方式。
master程序主要用來管理worker程序,包含:接收來自外界的信号,向各worker程序發送信号,監控worker程序的運作狀态,當worker程序退出後(異常情況下),會自動重新啟動新的worker程序。
worker程序則是處理基本的網絡事件。多個worker程序之間是對等的,他們同等競争來自用戶端的請求,各程序互相之間是獨立的。一個請求,隻可能在一個worker程序中處理,一個worker程序,不可能處理其它程序的請求。
worker程序的個數是可以設定的,一般我們會設定與機器cpu核數一緻。更多的worker數,隻會導緻程序來競争cpu資源了,進而帶來不必要的上下文切換。而且,nginx為了更好的利用多核特性,具有cpu綁定選項,我們可以将某一個程序綁定在某一個核上,這樣就不會因為程序的切換帶來cache的失效。
每個worker程序都是從master程序fork過來。在master程序裡面,先建立好需要listen的socket之後,然後再fork出多個worker程序,這樣每個worker程序都可以去accept這個socket(當然不是同一個socket,隻是每個程序的這個socket會監控在同一個ip位址與端口,這個在網絡協定裡面是允許的)。一般來說,當一個連接配接進來後,所有在accept在這個socket上面的程序,都會收到通知,而隻有一個程序可以accept這個連接配接,其它的則accept失敗。
程序之間不共享資源,不需要加鎖,是以省掉了鎖帶來的開銷。
采用獨立的程序,可以讓互相之間不會影響,一個程序退出後,其它程序還在工作,服務不會中斷,master程序則很快重新啟動新的worker程序。
程式設計上更加容易。
而多線程在多并發情況下,線程的記憶體占用大,線程上下文切換造成cpu大量的開銷。想想apache的常用工作方式(apache也有異步非阻塞版本,但因其與自帶某些子產品沖突,是以不常用),每個請求會獨占一個工作線程,當并發數上到幾千時,就同時有幾千的線程在處理請求了。這對作業系統來說,是個不小的挑戰,線程帶來的記憶體占用非常大,線程的上下文切換帶來的cpu開銷很大,自然性能就上不去了,而這些開銷完全是沒有意義的。
異步的概念和同步相對的,也就是不是事件之間不是同時發生的。
非阻塞的概念是和阻塞對應的,阻塞是事件按順序執行,每一事件都要等待上一事件的完成,而非阻塞是如果事件沒有準備好,這個事件可以直接傳回,過一段時間再進行處理詢問,這期間可以做其他事情。但是,多次詢問也會帶來額外的開銷。
總的來說,nginx采用異步非阻塞的好處在于:
不需要建立線程,每個請求隻占用少量的記憶體
沒有上下文切換,事件處理非常輕量
淘寶tengine團隊說測試結果是“24g記憶體機器上,處理并發請求可達200萬”。