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  

NewImage

368行 ngx_init_signals函數 設置要監聽的信號,和信號的處理函數

 

src/core/nginx.c  

NewImage

291-293行 信號為sig->signo,對應的處理函數為sig->handler

 

sig的定義如下

NewImage

QUIT和USR2的信號處理函數都為 ngx_signal_handler

對應的流程圖為

NewImage

 

 

2、master進程通過sigsuspend掛起在信號監聽處

NewImage

 

3,向master進程id發送USR2信號

ngx_signal_handler處理USR2信號

src/os/unix/ngx_process.c

NewImage

372行  設置了ngx_change_binary=1

 

master進程接收到信號,從掛起狀態恢復,繼續執行

src/os/unix/ngx_process.c

NewImage

277行 ngx_exec_new_binary通過fork啟動新的nginx bin文件

 

src/core/nginx.c

NewImage

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

NewImage

src/os/unix/ngx_process.c

NewImage

src/os/unix/ngx_process.c

 

對應的流程圖如下

 

NewImage

 

4、向老的nginx進程發送QUIT信號,從容關閉

master進程收到QUIT信號后,將ngx_quit置為1

NewImage

master進程接收到信號,從掛起狀態恢復,繼續執行

NewImage

209行 ngx_signal_worket_processes 向worker進程發送 NGX_SHUTDOWN_SIGNAL(QUIT)信號

215行 ngx_close_socket 主進程關閉監聽的socket

 

src/os/unix/ngx_process_cycle.c

NewImage

504行 通過kill函數向所有worker進程發送信號

 

5、worker進程收到NGX_SHUTDOWN_SIGNAL(QUIT)信號

src/os/unix/ngx_process.c 

NewImage

360行 worker進程將ngx_quit置為1

NewImage

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

NewImage

1024行 調用各個模塊的exit_process方法

1067行 銷毀內存池

對應的流程圖如下

NewImage 

 

6、子進程退出后,作為父進程的master進程會收到SIGCHLD信號

src/os/unix/ngx_process.c

NewImage

387行 父進程收到SIGCHLD后將ngx_reap置為1,

437行 發現信號是SIGCHLD后執行ngx_process_get_status函數判斷worker子進程是正常退出,還是異常退出

 

src/os/unix/ngx_process.c

NewImage

494-499行 如果發現worker子進程如果是正常退出的,會將exited置為1

 

master進程接收到信號,從掛起狀態恢復,繼續執行

NewImage

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

NewImage

619 如果worker至今才是因為意外退出的,並且可以重啟,則調用ngx_spawn_process重新啟動一個worker子進程

642 如果有worker進程還在運行則live=1 如果全部的worker子進程都已經退出則live=0

 

src/os/unix/ngx_process_cycle.c

NewImage

656行 ngx_delete_pidfile 刪除pid文件

666行 ngx_close_listening_sockets 關閉監聽端口

685行 銷毀內存池

686行 退出

對應的流程圖如下

NewImage

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM