Nginx master工作流程

master工作流程圖


這裏寫圖片描述

      master進程不需要處理網絡事件,它不負責業務的執行,只會通過管理worker等子進程來實現重啓服務、平滑升級、更換日誌文件、配置文件實時生效等功能。
      它會通過檢查一下7個標誌位來決定ngx_master_process_cycle函數的運行(和worker檢查4個標誌位是差不多的):
1. sig_atomic ngx_reap;
2. sig_atomic ngx_terminate;
3. sig_atomic ngx_quit;
4. sig_atomic ngx_reconfigure;
5. sig_atomic ngx_reopen;
6. sig_atomic ngx_change_binary;
7. sig_atomic ngx_noaccept;
8. ngx_uint_t ngx_restart; //這個不是信號

信號的意義

信號 對應進程中的全局標誌變量 意義
QUIT ngx_quit 優雅地關閉整個服務
TERM或者INT ngx_terminate 強制關閉整個服務
USR1 ngx_reopen 重新打開服務中的所有文件
WINCH ngx_noaccept 所有子進程不再接受處理新的連接,相當於對所有子進程發送QUIT信號
USR2 ngx_change_binary 平滑升級到新版本Nginx程序
HUP ngx_reconfigure 重新讀取配置文件是服務對新配置項生效
CHILD ngx_reap 有子進程意外結束,這時需要監控所有的子進程,也就是ngx_reap_children做的工作

ngx_processes全局數組

      在瞭解master的工作流程之前,先了解一下管理子進程的數據結構:ngx_processes全局數組中的元素ngx_process_t。

//定義1024個元素的ngx_processes數組,即最多隻能有1024個子進程
#define NGX_MAX_PROCESSES   1024

//當前操作的進程在ngx_processes數組中的下標
ngx_int_t   ngx_process_slot;

//ngx_processes數組中有意義的ngx_process_t元素中最大的下標
ngx_int_t   ngx_last_process;

//存儲所有子進程的數組
ngx_process_t   ngx_processes[NGX_MAX_PROCESSES];

typedef struct {
    //進程ID
    ngx_pid_t       pid;
    //由waitpid系統調用獲取的子進程狀態
    int             status;
    /* 用於master和worker之間通信的socket */
    ngx_socket_t    channel[2];
    //子進程的循環執行方法,當父進程調用ngx_spawn_process生成子進程時使用
    ngx_spawn_proc_pt   proc;
    /* 上面的方法第二個參數需要傳遞一個指針,它是可選的(因爲分爲worker、cache manager等)。
    這個data一般與第二個參數等價 */
    void            *data;
    //進程名。
    char            *name;
    //1:重新生成子進程
    unsigned        respawn:1;
    //1:正在生成子進程
    unsigned        just_spawn:1;
    //1:正在進行父進程、子進程分離
    unsigned        detached:1;
    //1:進程正在退出
    unsigned        exiting:1;
    //1:進程已退出
    unsigned        exited:1;
}   ngx_process_t;

master啓動一個子進程

      ngx_spawn_process函數封裝了fork()系統調用。它會從ngx_processes中選擇一個還未使用的ngx_process_t元素,存儲這個子進程的相關信息。錯誤將返回NGX_INVALID_PID。

//ngx_spawn_process格式   
ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle,ngx_spawn_proc_pt proc,void *data,char *name,ngx_int_t respawn);

      上述的proc方法就是要填入ngx_process_t中,子進程中將要執行的工作循環:

typedef void (*ngx_spawn_proc_pt)(ngx_cycle_t *cycle,void *data);

      worker進程、cache manage進程、cache loader進程都是依照該方法來定義的。

master工作流程

      事實上,master通過ngx_processes數組中的有效ngx_process_t元素內容來判斷一個子進程的狀態的,而信息的傳遞是通過Linux內核發來的CHILD信號。此時處理信號的ngx_signal_handler函數會將sig_reap置位,調用ngx_process_get_status函數來修改ngx_processes數組中所有子進程的狀態。

實際的工作流程(循環判斷8個標誌位):
1. 檢查ngx_reap標誌位。0:沒有子進程意外退出,進入下一步;1:利用ngx_reap_children遍歷ngx_processes數組,對於非正常退出的子進程重新拉起。如果所有子進程都正常退出,返回一個live=0,否則live=1;
2. 如果live=0:所有子進程已經退出、ngx_terminate=1或者ngx_quit=1,都會調用ngx_master_process_exit函數退出master進程,否則跳到第6步。若live=1,表用還有子進程存在,進入第6步;
3. 調用ngx_master_process_exit函數,其中調用所有模塊的exit_master函數;
4. 調用ngx_close_listening_sockets關閉進程中打開的監聽端口;
5. 銷燬內存池,退出master;
6. 如果ngx_terminate=1,則向所有子進程發送信號TERM,通知子進程強制退出,接下來直接跳到第1步,等待信號激活進程;否則繼續下一步;
7. 如果ngx_quit=0,跳到第9步,否則向所有子進程發送QUIT信號,優雅地退出;
8. 發送完QUIT信號後,關閉所有端口,跳到第1步,掛起master進程,等待信號激活;
9. 如果ngx_reconfigure=0,則跳到第13步檢查ngx_restart標誌位。如果爲1,則需要重新讀取配置文件。Nginx會初始化新的ngx_cycle_t結構體,用它讀取新的配置文件,重新拉起新的worker進程,銷燬舊的。
10. 接着調用ngx_start_process方法在拉起一批worker進程,這些worker進程將使用新的ngx_cycle_t結構體。
11. 然後調用ngx_start_cache_manager_processes按照緩存模塊的加載情況決定是否拉起新的cache manage或者cache loader進程。這個兩個方法調用後一定存在子進程,於是將live置位。
12. 接着11步,向原先的(舊的)所有子進程發送QUIT信號,優雅地退出。
13. 檢查ngx_restart標誌位。0:跳到15步;1:調用ngx_start_worker_processes拉起worker進程,同時將ngx_restart復位。
14. 接着調用ngx_start_cache_manager_processes根據緩存情況選擇是否啓動cache manage進程或者cache loader進程,同時將live置位。
15. 檢查ngx_reopen標誌位。0:跳到17步;1:調用ngx_reopen_files重新打開所有文件,並將ngx_reopen復位。
16. 向所有子進程發送USR1信號,要求子進程都得重新打開所有文件。
17. 檢查ngx_change_binary標誌位。1:需要平滑升級Nginx,這是將調用ngx_exec_new_binary函數,用新的子進程啓動新版本的Nginx程序,同時將ngx_change_binary復位。
18. 檢查ngx_noaccept標誌位。0:跳到第1步,進入下一個循環;1:向所有子進程發送QUIT信號,要求它們優雅地關閉服務,同時將ngx_noaccept復位,將ngx_noaccpeting置位,表示正在停止接受新的連接。

      master進程並不是busy loop,而是會通過sigsuspend系統調用,讓master進程休眠,等待master進程收到信號後激活master進程。

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