1)若是採用阻塞調用的方式,當讀寫事件沒有準備好時,必然不可以進行讀寫事件,那麼久只好等待,等事件準備好了,才能進行讀寫事件。那麼請求就會被耽擱 。阻塞調用會進入內核等待,cpu就會讓出去給別人用了,對單線程的worker來講,顯然不合適,當網絡事件越多時,你們都在等待呢,cpu空閒下來沒 人用,cpu利用率天然上不去了,更別談高併發了 。 前端
2)既然沒有準備好阻塞調用不行,那麼採用非阻塞方式。非阻塞就是,事件,立刻返回EAGAIN,告訴你,事件還沒準備好呢,你慌什麼,過會再來吧。好 吧,你過一會,再來檢查一下事件,直到事件準備好了爲止,在這期間,你就能夠先去作其它事情,而後再來看看事件好了沒。雖然不阻塞了,但你得不時地過來檢 查一下事件的狀態,你能夠作更多的事情了,但帶來的開銷也是不小的
nginx
小結:非阻塞經過不斷檢查事件的狀態來判斷是否進行讀寫操做,這樣帶來的開銷很大。 web
3)所以纔有了異步非阻塞的事件處理機制。具體到系統調用就是像select/poll/epoll/kqueue這樣的系統調用。他們提供了一種機制, 讓你能夠同時監控多個事件,調用他們是阻塞的,但能夠設置超時時間,在超時時間以內,若是有事件準備好了,就返回。這種機制解決了咱們上面兩個問題。以epoll爲例:當事件沒有準備好時,就放入epoll(隊列)裏面。若是有事件準備好了,那麼就去處理;若是事件返回的是EAGAIN,那麼繼 續將其放入epoll裏面。從而,只要有事件準備好了,咱們就去處理她,只有當全部時間都沒有準備好時,纔在epoll裏面等着。這樣,咱們就能夠併發處 理大量的併發了,固然,這裏的併發請求,是指未處理完的請求,線程只有一個,因此同時能處理的請求固然只有一個了,只是在請求間進行不斷地切換而已,切換 也是由於異步事件未準備好,而主動讓出的。這裏的切換是沒有任何代價,你能夠理解爲循環處理多個準備好的事件,事實上就是這樣的。 後端
小結:經過異步非阻塞的事件處理機制,Nginx實現由進程循環處理多個準備好的事件,從而實現高併發和輕量級。
瀏覽器
Nginx特色:
1. 跨平臺:Nginx 能夠在大多數 Unix like OS編譯運行,並且也有Windows的移植版本。
2. 配置異常簡單,很是容易上手。配置風格跟程序開發同樣,神通常的配置
3. 非阻塞、高併發鏈接:數據複製時,磁盤I/O的第一階段是非阻塞的。官方測試可以支撐5萬併發鏈接,在實際生產環境中跑到2~3萬併發鏈接數.(這得益於Nginx使用了最新的epoll模型)
4. 事件驅動:通訊機制採用epoll模型,支持更大的併發鏈接。 緩存
5. nginx代理和後端web服務器間無需長鏈接;
6. 接收用戶請求是異步的,即先將用戶請求所有接收下來,再一次性發送後後端web服務器,極大的減輕後端web服務器的壓力
7. 發送響應報文時,是邊接收來自後端web服務器的數據,邊發送給客戶端的
8. 網絡依賴型低。NGINX對網絡的依賴程度很是低,理論上講,只要可以ping通就能夠實施負載均衡,並且能夠有效區份內網和外網流量
9. 支持服務器檢測。NGINX可以根據應用服務器處理頁面返回的狀態碼、超時信息等檢測服務器是否出現故障,並及時返回錯誤的請求從新提交到其它節點上 服務器
master/worker結構:一個master進程,生成一個或多個worker進程 網絡
內存消耗小:處理大併發的請求內存消耗很是小。在3萬併發鏈接下,開啓的10個Nginx 進程才消耗150M內存(15M*10=150M) 成本低廉:Nginx爲開源軟件,能夠無償使用。而購買F5 BIG-IP、NetScaler等硬件負載均衡交換機則須要十多萬至幾十萬人民幣
內置的健康檢查功能:若是 Nginx Proxy 後端的某臺 Web 服務器宕機了,不會影響前端訪問。
節省帶寬:支持 GZIP 壓縮,能夠添加瀏覽器本地緩存的 Header 頭。
穩定性高:用於反向代理,宕機的機率微乎其微 多線程
nginx是以多進程的方式來工做的,固然nginx也是支持多線程的方式的,只是咱們主流的方式仍是多進程的方式,也是nginx的默認方式。nginx採用多進程的方式有諸多好處 .
(1) nginx在啓動後,會有一個master進程和多個worker進程。master進程主要用來管理worker進程,包含:接收來自外界的信號,向各 worker進程發送信號,監控 worker進程的運行狀態,當worker進程退出後(異常狀況下),會自動從新啓動新的worker進程。而基本的網絡事件,則是放在worker進 程中來處理了 。多個worker進程之間是對等的,他們同等競爭來自客戶端的請求,各進程互相之間是獨立的 。一個請求,只可能在一個worker進程中處理,一個worker進程,不可能處理其它進程的請求。 worker進程的個數是能夠設置的,通常咱們會設置與機器cpu核數一致,這裏面的緣由與nginx的進程模型以及事件處理模型是分不開的 。 併發
(2)Master接收到信號之後怎樣進行處理(./nginx -s reload )?
首先master進程在接到信號後,會先從新加載配置文件,而後再啓動新的進程,並向全部老的進程發送信號,告訴他們能夠光榮退休了。新的進程在啓動後, 就開始接收新的請求,而老的進程在收到來自master的信號後,就再也不接收新的請求,而且在當前進程中的全部未處理完的請求處理完成後,再退出 .
3) worker進程又是如何處理請求的呢?
咱們前面有提到,worker進程之間是平等的,每一個進程,處理請求的機會也是同樣的。當咱們提供80端口的http服務時,一個鏈接請求過來,每一個進程 都有可能處理這個鏈接,怎麼作到的呢?首先,每一個worker進程都是從master進程fork過來,在master進程裏面,先創建好須要 listen的socket以後,而後再fork出多個worker進程,這樣每一個worker進程均可以去accept這個socket(固然不是同一 個socket,只是每一個進程的這個socket會監控在同一個ip地址與端口,這個在網絡協議裏面是容許的)。通常來講,當一個鏈接進來後,全部在 accept在這個socket上面的進程,都會收到通知,而只有一個進程能夠accept這個鏈接,其它的則accept失敗,這是所謂的驚羣現象。當 然,nginx也不會視而不見,因此nginx提供了一個accept_mutex這個東西,從名字上,咱們能夠看這是一個加在accept上的一把共享 鎖。有了這把鎖以後,同一時刻,就只會有一個進程在accpet鏈接,這樣就不會有驚羣問題了。accept_mutex是一個可控選項,咱們能夠顯示地 關掉,默認是打開的。當一個worker進程在accept這個鏈接以後,就開始讀取請求,解析請求,處理請求,產生數據後,再返回給客戶端,最後才斷開 鏈接,這樣一個完整的請求就是這樣的了。咱們能夠看到,一個請求,徹底由worker進程來處理,並且只在一個worker進程中處理。
4) nginx採用這種進程模型有什麼好處呢?
採用獨立的進程,可讓互相之間不會影響,一個進程退出後,其它進程還在工做,服務不會中斷,master進程則很快從新啓動新的worker進程。當 然,worker進程的異常退出,確定是程序有bug了,異常退出,會致使當前worker上的全部請求失敗,不過不會影響到全部請求,因此下降了風險。 固然,好處還有不少,你們能夠慢慢體會。
(5) nginx採用多worker的方式來處理請求,每一個worker裏面只有一個主線程,那可以處理的併發數頗有限啊,多少個worker就能處理多少個並 發,何來高併發呢?非也,這就是nginx的高明之處,nginx採用了異步非阻塞的方式來處理請求,也就是說,nginx是能夠同時處理成千上萬個請求 的 .
對於IIS服務器每一個請求會獨佔一個工做線程,當併發數上到幾千時,就同時有幾千的線程在處理請求了。這對操做系統來講,是個不小的挑戰,線程帶來 的內存佔用很是大,線程的上下文切換帶來的cpu開銷很大,天然性能就上不去了,而這些開銷徹底是沒有意義的。咱們以前說過,推薦設置worker的個數 爲cpu的核數,在這裏就很容易理解了,更多的worker數,只會致使進程來競爭cpu資源了,從而帶來沒必要要的上下文切換。並且,nginx爲了更好 的利用多核特性,提供了cpu親緣性的綁定選項,咱們能夠將某一個進程綁定在某一個核上,這樣就不會由於進程的切換帶來cache的失效
負載均衡
負載均衡技術在現有網絡結構之 上提供了一種廉價、有效、透明的方法,來擴展網絡設備和服務器的帶寬、增長吞吐量、增強網絡數據處理能力、提升網絡的靈活性和可用性。它有兩方面的含義: 首先,大量的併發訪問或數據流量分擔到多臺節點設備上分別處理,減小用戶等待響應的時間;其次,單個重負載的運算分擔到多臺節點設備上作並行處理,每一個節 點設備處理結束後,將結果彙總,返回給用戶,系統處理能力獲得大幅度提升