nginx學習 --- 進程管理

初步理解nginx 進程管理nginx

niginx啓動後會有一個master和多個worker進程。master進程主要用來管理worker 進程。包括:接受外界信號,向各worker進程發送信號,監控worker進程的運行狀態,當worker進程退出後(異常狀況下),會自動重啓新的worker進程。而基本的網絡事件,則是在worker進程中處理。多個worker進程之間是對等的,他們的同等競爭來自客戶端的請求,但他們之間又是相互對立的。一個請求只能在一個worker進程中處理,一個worker進程不可能處理其餘進程的請求。worker進程的個數是能夠設置。通常會和機器的CPU個數設置一致(這裏的緣由是和nginx的進程模型以及事件處理模型分不開的)。web

nginx 的進程模型以下圖:服務器

 

在nginx 啓動後,管理nginx 只須要與master 進程通訊就行了。master進程會接受來自外界信號。再根據信號作不一樣的事情。因此控制nginx只須要 kill master 進程發信號就能夠了(如:kill -HUP pid  則是重啓 nginx  )。網絡

簡單描述一下重啓nginx後的進程狀態:當重啓nginx後,master在接到信號後,會重現加載配置文件,而後啓動新的worker進程,並告訴舊的worker進程,他們能夠下崗了。新的worker在啓動後,就開始接受新的請求,而老的worker就再也不接受請求,而當前進程在全部未處理完的請求處理完成後退出。多線程

那麼nginx 內部是如何處理請求的呢? 每一個worker進程都是從master進程fork(叉分)過來的。在master進程裏面,先創建號須要listen和socket(listenefd)以後,而後再fork 多個work 進程。全部worker進程的listenfd會在新的鏈接到來的時候變得可讀,爲保證只有一個進程處理該鏈接,全部worker進程在註冊listenefd  讀事件前搶 accept_mutex , 搶到互斥鎖的那個進程註冊listenefd讀事件,在讀事件裏調用accept接受該鏈接。當一個worker進程在accept這個進程後,就開始讀取請求,處理請求,產生數據後 ,再返回個客戶端,最後才斷開鏈接,這樣一個完整的請求就是這樣了。併發

上面闡述了nginx進程模型,那麼nginx是如何處理事件的。異步

nginx 採用了異步非阻塞的方式來處理請求,即nginx是能夠同時處理成千上萬個請求的。socket

如今來看一個完整的請求過程。首先,請求過來,要創建鏈接,而後再接受數據,接受數據後,再發送數據,具體到系統底層,就是讀寫事件,而當讀寫事件沒有準備好時,必然不可操做,若是不用非阻塞的方式來調用,那就的阻塞調用了,事件沒有準備好,那就只能等用,cpu利用率天然就下來了,更不可能高併發了。全部,在nginxl裏面,最忌諱阻塞的系統調用了,不要阻塞即非阻塞了。非阻塞就是,事件沒有準備好,立刻返回EAGEAIN(eagin),表示事件尚未準備好,過會再來,再檢查一下事件,直到事件準備好了爲止,雖然不阻塞,但要時不時檢查一下事件的狀態,因此纔有了事件處理機制,具體到系統調用就像 /select/poll/epoll/kqueue 這樣的系統調用。他們提供了一種機制,能夠同時監控多個事件,調用他們是阻塞的,但能夠設置超時時間,在超時時間以內,若是有事件準備好了,就返回。固然線程的個數只有一個,因此同時能處理的請求只有一個,只是在請求間進程不斷的切換而已,切換也是由於異步事件未準備好,而主動讓出的。這裏的切換是沒有任何代價。也能夠理解爲循環多個準備好的事件。與多線程相比,這種事件處理方式是有很大優點的。不須要建立線程,每一個請求佔用的內存也很小,處理的事件也很是的輕量級。併發的數量再多也不會致使無謂的資源浪費。函數

對於一個基本的web服務器來講,事件一般有三種模型,網絡事件,信號,定時器。 網絡事件經過異步阻塞的方式能夠很好的解決。就剩下定時器和信號了。信號 ,特定的信號表明着特殊的意義。信號會中斷掉當前程序的運行,在改變狀態後,繼續執行。若是隻是系統調用。則可能會致使系統調用失敗。因此信號處理後續學習。定時器,在事件準備的時候,能夠設置一個超時時間的,在算出等待的超時時間後進入事件處理狀態。因此,當沒有事件產生,也沒有中斷信號時,等待處理的事件會超時 ,這是就有了定時器事件了。這時,nginx 會檢查全部的超時事件,講他們設置爲超時,而後在處理網絡事件。因此在吃力網絡事件的回調函數的時,一般第一件事情就是判斷超時,而後處理網絡事件。高併發

相關文章
相關標籤/搜索