1. 程式人生 > 其它 >4.nginx原理

4.nginx原理

https://blog.csdn.net/liupeifeng3514/article/details/79857060

https://www.cnblogs.com/chenjfblog/p/8715580.html
    
https://blog.csdn.net/hhhzua/article/details/79294735
1.Nginx在啟動後,會有一個master程序和多個worker程序:
  worker程序的數量如何控制呢?
     nginx.conf配置檔案中有一個worker_processes配置項,預設配置為:
         worker_processes 1
    worker程序的數量會直接影響效能。
    每一個worker程序都是單執行緒程序,它們呼叫各個模組以實現多種多樣的功能,如果這些模組確認不會出現阻塞式呼叫,
    那麼,有多少個CPU核心就配置多少個worker程序,如果有可能出現阻塞式呼叫,就需要稍多一些worker程序 
    
    例如 :
    如果業務需要大量讀取磁碟上的靜態檔案,而且伺服器上的記憶體較小,以至於大部分的請求訪問靜態檔案時都必須讀取磁碟,
    而不是記憶體中的磁碟快取,那麼磁碟I/O呼叫可能會阻塞住worker程序少量時刻,進而導致服務整體效能下降。
    多worker程序可以充分利用多核系統架構,但若worker程序的數量多於CPU核心數,那麼會增大程序間切換帶來的消耗(Linux是搶佔式核心)。 
    一般情況下,使用者配置與核心數相等的worker程序,並使用worker_cpu_affinity配置來繫結CPU核心


1.master程序
    master程序主要用來管理worker程序,包含
        1.接收來自外界的訊號;
        2.向各worker程序傳送訊號;
        3.監控worker程序的執行狀態,當worker程序退出後(異常情況下),會自動重新啟動新的worker程序。
master程序充當整個程序組與使用者的互動介面,同時對程序進行監護。它不需要處理網路事件,不負責業務的執行,
只會通過管理worker程序來實現重啟服務、平滑升級、更換日誌檔案、配置檔案實時生效等功能。
我們要控制nginx,只需要通過kill向master程序傳送訊號就行了。比如kill -HUP pid,則是告訴nginx,從容地重啟nginx,
我們一般用這個訊號來重啟nginx,或重新載入配置,因為是從容地重啟,因此服務是不中斷的。

master程序在接收到HUP訊號後是怎麼做的呢?首先master程序在接到訊號後,會先重新載入配置檔案,然後再啟動新的worker程序,
並向所有老的worker程序傳送訊號,告訴他們可以光榮退休了。新的worker在啟動後,就開始接收新的請求,而老的worker在收到來自master的訊號後,
就不再接收新的請求,並且在當前程序中的所有未處理完的請求處理完成後,再退出。當然,直接給master程序傳送訊號,這是比較老的操作方式,
nginx在0.8版本之後,引入了一系列命令列引數,來方便我們管理。比如,./nginx -s reload,就是來重啟nginx,./nginx -s stop,就是來停止nginx的執行。
如何做到的呢?我們還是拿reload來說,我們看到,執行命令時,我們是啟動一個新的nginx程序,而新的nginx程序在解析到reload引數後,
就知道我們的目的是控制nginx來重新載入配置檔案了,它會向master程序傳送訊號,然後接下來的動作,就和我們直接向master程序傳送訊號一樣了。

worker程序
而基本的網路事件,則是放在worker程序中來處理了。多個worker程序之間是對等的,他們同等競爭來自客戶端的請求,各程序互相之間是獨立的。
一個請求,只可能在一個worker程序中處理,一個worker程序,不可能處理其它程序的請求。
worker程序的個數是可以設定的,一般我們會設定與機器cpu核數一致,這裡面的原因與nginx的程序模型以及事件處理模型是分不開的。
worker程序之間是平等的,每個程序,處理請求的機會也是一樣的。當我們提供80埠的http服務時,一個連線請求過來,每個程序都有可能處理這個連線,怎麼做到的呢?
首先,每個worker程序都是從master程序fork過來,在master程序裡面,先建立好需要listen的socket(listenfd)之後,然後再fork出多個worker程序。
所有worker程序的listenfd會在新連線到來時變得可讀,為保證只有一個程序處理該連線,所有worker程序在註冊listenfd讀事件前搶accept_mutex,
搶到互斥鎖的那個程序註冊listenfd讀事件,在讀事件裡呼叫accept接受該連線。當一個worker程序在accept這個連線之後,
就開始讀取請求,解析請求,處理請求,產生資料後,再返回給客戶端,最後才斷開連線,這樣一個完整的請求就是這樣的了。
我們可以看到,一個請求,完全由worker程序來處理,而且只在一個worker程序中處理。