Nginx平滑升級源碼分析,nginx源碼
一、平滑升級步驟
1、重新命名之前的sbin/nginx檔案,將新的nginx檔案放到sbin/目錄下
#mv ./sbin/nginx ./sbin/nginx.old
#cp ~/nginx ./sbin/
2、向正在啟動並執行nginx發送USR2訊號啟動新的nginx,這個時候新老nginx都會接收請求,看那一個進程能搶到鎖,搶到鎖的worker進程可以accpet新請求
#kill -USR2 `cat nginx.pid`
3、觀察新的nginx運行無誤後,向舊nginx發訊號 停止舊nginx的運行
#kill -QUIT `cat nginx.pid.oldbin`
二、源碼分析
1,nginx啟動時 設定訊號監聽函數,監聽訊號
src/core/nginx.c
368行 ngx_init_signals函數 設定要監聽的訊號,和訊號的處理函數
src/core/nginx.c
291-293行 訊號為sig->signo,對應的處理函數為sig->handler
sig的定義如下
QUIT和USR2的訊號處理函數都為 ngx_signal_handler
對應的流程圖為
2、master進程通過sigsuspend掛起在訊號監聽處
3,向master進程id發送USR2訊號
ngx_signal_handler處理USR2訊號
src/os/unix/ngx_process.c
372行 設定了ngx_change_binary=1
master進程接收到訊號,從掛起狀態恢複,繼續執行
src/os/unix/ngx_process.c
277行 ngx_exec_new_binary通過fork啟動新的nginx bin檔案
src/core/nginx.c
589行 ngx_set_evviroment 設定新nginx bin的環境變數
640行 ngx_rename_file 通過rename函數將nginx.pid檔案重新命名為nginx.pid.oldbin
651行 ngx_execute 啟動新的bin檔案
由於nginx老master進程fork出的新nginxmaster進程,他們可以監聽同一個連接埠,所以新nginx和老nginx可以同時監聽連接埠,具體誰執行看哪一個worker子進程搶到了鎖,可以accpet新串連
src/os/unix/ngx_process.c
src/os/unix/ngx_process.c
src/os/unix/ngx_process.c
對應的流程圖如下
4、向老的nginx進程發送QUIT訊號,從容關閉
master進程收到QUIT訊號後,將ngx_quit置為1
master進程接收到訊號,從掛起狀態恢複,繼續執行
209行 ngx_signal_worket_processes 向worker進程發送 NGX_SHUTDOWN_SIGNAL(QUIT)訊號
215行 ngx_close_socket 主進程關閉監聽的socket
src/os/unix/ngx_process_cycle.c
504行 通過kill函數向所有worker進程發送訊號
5、worker進程收到NGX_SHUTDOWN_SIGNAL(QUIT)訊號
src/os/unix/ngx_process.c
360行 worker進程將ngx_quit置為1
worker進程收到訊號後從epoll_wait中喚醒從ngx_process_events_and_timers函數中恢複,
710-714行 發現ngx_quit=1後將ngx_quit恢複為0,ngx_exiting置為1,
713行 通過ngx_close_listening_sockets關閉處理的socket
609行 下一次迴圈發現ngx_exiting=1後,處理隊列中的已有事件和逾時事件,發現沒有要處理的事件了,就通過ngx_worker_process_exit退出worker進程
src/os/unix/ngx_process_cycle.c
1024行 調用各個模組的exit_process方法
1067行 銷毀記憶體池
對應的流程圖如下
6、子進程退出後,作為父進程的master進程會收到SIGCHLD訊號
src/os/unix/ngx_process.c
387行 父進程收到SIGCHLD後將ngx_reap置為1,
437行 發現訊號是SIGCHLD後執行ngx_process_get_status函數判斷worker子進程是正常退出,還是異常退出
src/os/unix/ngx_process.c
494-499行 如果發現worker子進程如果是正常退出的,會將exited置為1
master進程接收到訊號,從掛起狀態恢複,繼續執行
176行 發現ngx_reap=1後,ngx_reap_children函數判斷是否需要重啟worker進程
如果worker是因為收到了quit訊號正常退出的,所有worker進程退出時,live=0
183行 live=0 並且收到了ngx_quit訊號 通過ngx_master_process_exit關閉master進程
src/os/unix/ngx_process_cycle.c
619 如果worker至今才是因為意外退出的,並且可以重啟,則調用ngx_spawn_process重新啟動一個worker子進程
642 如果有worker進程還在運行則live=1 如果全部的worker子進程都已經退出則live=0
src/os/unix/ngx_process_cycle.c
656行 ngx_delete_pidfile 刪除pid檔案
666行 ngx_close_listening_sockets 關閉監聽連接埠
685行 銷毀記憶體池
686行 退出
對應的流程圖如下
PS:推薦一個好朋友的公眾號,一個每天都在思考或者在思考路上的公眾號運營少女~