深度學習Nginx第三章:Nginx請求流程和進程結構

        學習這方面知識主要解決問題:Nginx一般部署在內網邊緣節點,它處理的流量一般比其他應用服務器流量數倍或者數個流量級別,所以在Nginx處理問題,所有問題都會被放大,所以我們要了解爲什麼要使用master和worker這種架構模型,並且worker必須要和cpu的核數所匹配,當我們在多個worker進程之間共享數據時,爲什麼在tls或者說限流、限速這些場景共享方式是有所不同的

 

Nginx請求處理流程

   

     當流量進入nginx,主要有三種狀態機,第一個是處理tcp、udp的四層傳輸層的,還有處理http應用層的,以及處理郵件的,因爲ningx是使用非阻塞的事件驅動處理引擎,爲什麼叫狀態機,是因爲這個綠色的框是使用非阻塞的事件驅動處理引擎(epoll),一旦我們使用異步的這種處理,都是使用狀態機識別和處理的

    另外當我們進行靜態資源磁盤緩存的時候,如果整個文件不足以緩存住的時候,像 sendfile這種調用,或者AIO會退化成阻塞的磁盤調用,所以使用線程池來進行處理磁盤阻塞調用,處理完成的請求記錄access日誌或者錯誤日誌

Nginx結構

    nginx有兩種進程結構,單進程結構和多進程結構,前者不適用生產環境,無法用到多核的特性,默認配置打開多進程。會有一個master進程,會有很多子進程,一類是worker進程,一類是cache相關進程,master進程設計出來是主要對worker進程進行監控管理的,看需不需要熱部署,是否需要重新載入配置文件,worker進程是真正對請求進行處理的,緩存是要在多個worker進程間進行共享的,而且緩存不僅被worker進程使用還要被cache manager和cache loader所使用,這兩個也是爲反向代理時,後端發出的動態請求做緩存進行處理的,前者是緩存的管理,後者是緩存的載入,這些進程間的通信使用共享內存來使用的,父子進程間是使用信號進行管理的

爲什麼Nginx採用的是多進程結構,而不是多線程結構?

 這是根據Nginx最核心的一個目的,nginx要保證它的高可用性和高可靠性,當Nginx採用多線程的時候,因爲線程之間共享同一個地址空間的,當某一個第三方模塊導致地址空間段錯誤時,可能會導致Nginx的線程全部掛掉,而我們採用多進程的時候,進程間不會共享地址空間就不會出現這個事情

爲什麼worker進程會很多?

這是因爲Nginx採用事件驅動模型,一個worker進程從頭到尾佔用一個cpu,我們不僅配置worker和cpu數量進行一致外還需要把worker和cpu綁定在一起,這樣可以更好使用cpu核上的cpu緩存,這樣減少緩存失效的命中率

使用信號管理Nginx的父子進程:通常進程間的通信使用共享內存和信號,而進程間的管理是使用的是信號

   其中能夠發送和處理信號的有Master進程、Worker進程、Nginx命令行,其中master進程進行對worker進行監控和管理,當worker因爲一些模塊bug等意外掛掉的時候會給master進程發送CHLD信號,然後master進程進行拉起一個新的worker進程,master進程還可以通過接受信號來進行管理worker進程,其中USR1是重新打開日誌文件做日誌文件切割、HUP重新載入等等,其中前四個是可以通過Nginx命令行加特定的命令來實現的,而後兩個做日誌的熱部署,是通過使用kill直接向master進程進行發送信號,通過對pid來執行USR2和WINCH,主要是對熱部署進行執行,worker也可以進行接收信號,但是平常不是對worker進程直接發送信號,而是對master進程進行發送信號來管理worker進程

   當我們啓動Nginx的時候,通常我們會把pid記錄到默認目錄下,Nginx安裝目錄下的文件中,那個Pid文件會記錄master進程的pid,這個時候我們執行nginx -s 這樣的命令時候,nginx會讀取master進程的pid,根據pid像master進程發送HUP、等信號,這些信號對應我們命令,所以我們調用nginx命令和直接kill 使用他們的信號是一樣的 SIGHUP等 例如:kill -SIGHUP 進程號 、kill -SIGTERM woker進程pid

reload重載配置文件

在不停止服務的情況下,平滑的把Nginx舊的config更新到新的config

 說明:從第二步我們可以知道不一定非要在nginx -reload之前執行 - t 檢驗一下語法是否正確,因爲在第二部的時候一定會做這件事,情,master會打開新的端口是因爲我們如果在nginx,config中引入了新的端口比如443等,所有woker進程是master進程的子進程,所有的子進程會繼承父進程打開的端口,這個是nginx操作系統所定義的,因爲平滑,所以要新起子進程然後在給老的worker子進程發送QUIT信號

如果有些請求出問題,客戶端長時間沒有處理,長時間佔用在worker進程上面,因爲新的連接是跑在黃色worker進程上面,所以影響不大,唯一導致綠色子進程長時間存在,解決辦法是nginx新的版本中存在一個配置項,woker_shutdown_timeout最長等多長時間,定時器,到了時間強制退出

 

熱升級完整流程

     在進行升級過程中還存在很多問題,比如老的worker進程退不掉,新的worker升級後出現新的問題,需要回滾,我們升級後可能存在指向的配置文件出現問題,具體操作

在第二步的時候沒有直接執行命令是因爲nginx目前沒有這樣的信號,master進程執行 3、4。新的master進程是老的master進程的子進程,怎麼找到老的master進程發送信號,我們通過ps -ef找到老的master進程,然後發送QUIT信號,但是老的master進程一直保存下來,就是方便我們回滾

 worker進程:如何優雅的關閉

     優雅的關閉時只對worker進程的,因爲處理的請求的是worker進程,如果直接關閉woker進程,可能導致用戶請求的時候返回一個錯誤。worker進程可以識別出當前是否有連接請求,這個時候把連接關閉,nginx對於有些請求是做不到這一點的,比如nginx代理 1、 websockt協議的時候,在websocket的數據幀的時候(WebSocket真正麻煩的地方是在數據的傳輸上!爲了環保,它使用了特定格式的數據幀,這個數據幀需要自己去解析,當然也有別人編寫好的庫可以用。雖然官方文檔描述的很詳細,但是看起來還是蛋疼),nginx是不解析的,2、nginx作爲tcp層或者udp層的反向代理時候是無法分辨出一個請求是需要經歷多少報文才算結束,但是對於http請求是可以做到。

    關閉流程1、設置定時器(worker_shutdown_timeout)、2、關閉監聽句柄(保證woker進程不會處理新的連接了)、3、關閉空閒連接(先去看連接處,因爲nginx爲了保證自己的對資源利用是最大化的,經常保存一些空閒的鏈接,但是沒有斷開)、4、再循環中等待全部鏈接關閉(時間較長,可能超過worker_shutdown_timeout,如果超過,直接關閉)、5、退出進程

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章